next.js 为什么我的页面在上下文更改时不重新呈现

fnatzsnv  于 6个月前  发布在  其他
关注(0)|答案(1)|浏览(48)

我有一个基本上下文,其中一些基本的东西是存储在像当前登录的用户。我有一个用户页面,应该显示的信息,但它不重新呈现时,上下文的变化。首先,上下文当然是空的(isLoaded = false)。当init(从API获取用户)完成后,isLoaded和base.loaded设置为true。上下文更新,但是用户页面没有更新,并且一直显示“正在加载..."。我的页面也被正确地 Package 在上下文中
内容:

"use client"

import { createContext, useContext, ReactNode, useState, useEffect } from 'react';
import Base from '@/scripts/classes/Base.class';

const BaseContext = createContext<Base | undefined>(undefined);

export const BaseProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
  const base = new Base("123");
  const [ isLoaded, setLoaded ] = useState(false);

  useEffect(() => {
    base.init()
      .then(() => {
        console.log("Initialized base")
        setLoaded(true);
       })
       .catch(() => { console.log("ERROR ON INITIALIZATION")})
  }, []);

  if(!isLoaded) return "Loading Base...";

  return <BaseContext.Provider value={base}>{children}</BaseContext.Provider>;
};

export const useBase = () => {
  const context = useContext(BaseContext);
  if (!context) {
    throw new Error("useBase must be used within a BaseProvider");
  }
  return context;
};

字符串
这是我的页面:

"use client"

export default function UserProfile({ params }: Props) {
    const base = useBase();

    if(!base.loaded) {
        return "Loading User...";
    } else {
        return "Loaded " + base.users.me.username;
    }
}


下面是我的基类:

export default class Base {
    loaded: boolean = false;
    users: UserManager;

    locale: any;

    api: API;
    websocket: Websocket;

    constructor(token: string) {
        this.users = new UserManager(this);
        this.api = new API(this, token);
        this.websocket = new Websocket();
    }

    async init() {
        this.users.me = await this.users.fetch(1);
        this.locale = { hello: "Hello" }; //Fetch from URL later

        this.loaded = true;
    }
}


我绝对确定base已经初始化,用户也设置正确,只是它没有更新页面。
我希望用户显示后,基地加载

drkbr07n

drkbr07n1#

React似乎并不直接检测类更新。
我通过在基础上添加一个“hash”和一个监视hash的状态来修复它。每次我更新一些东西时,我都必须调用this.update(),它会更改hash并触发setState
我很确定有更好的方法,但就目前而言,这是我找到的最好的方法。
基本供应商:

const BaseContext = createContext<Base | undefined>(undefined);

export const BaseProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
  const [ base, setBase ] = useState<Base | undefined>(undefined);
  

  useEffect(() => {
    (async () => {
      const _base = new Base("123");
      await _base.init();

      setBase(_base);
    })();
  }, []);

  if(!base || !base.loaded) return "Loading Overlay"

  return (
    <BaseContext.Provider value={ base }>
      {children}
    </BaseContext.Provider>
  );
};

export const useBase = () => {
  const context = useContext(BaseContext);
  
  const [ _, setBaseHash ] = useState(Math.random());
  context?.onUpdate(() => setBaseHash(context.hash));

  if (!context) {
    throw new Error("useBase must be used within a BaseProvider");
  }
  return context;
};

字符串
基类:

export default class Base {
    hash: number = 0;
    loaded: boolean = false;
    users: UserManager;

    locale: any;

    api: API;
    websocket: Websocket;

    private updateListeners: Function[] = [];

    constructor(token: string) {
        this.users = new UserManager(this);
        this.api = new API(this, token);
        this.websocket = new Websocket();
    }

    async init() {
        await this.users.fetch(1);
        //this.locale = fetch from url...;

        this.loaded = true;

        await this.websocket.connect(config.socketUrl);
        this.websocket.authorize(this.api.token, [ "Users" ]);
            
        this.websocket.on("UserUpdate", (newUser: Partial<UserStructure>) => {
           //update this.users.cache logic

            this.update();
        })
    }

    onUpdate(fn: Function) {
        this.updateListeners.push(fn);
    }

    update() {
        this.hash = Math.random();
        this.updateListeners.forEach(fn => fn());
    }
}


这是一个很好的例子。

export default function UserProfile({ params }: Props) {
    const base = useBase();

    const userId = parseInt(params.userId) || 0;
    const user = base.users.cache.get(userId);

    if(!user) return "User not found";

   //do something with user
}

相关问题