React 上下文的值未更新

Value of react context is not updated

我有一个用 react typescript 实现的客户端,它需要处理用户数据。 因此,我创建了一个 AppContext。

//appState.ts

export interface UserStateProperties {
    authenticated: boolean,
    user: GetUserResponse | undefined,
    notificationManager: NotificationManager | undefined
}

export interface AppContextProperties {
    userState: UserStateProperties,
    setUserState: Dispatch<SetStateAction<UserStateProperties>>
}

const AppContext = React.createContext<AppContextProperties>({ 
    userState: {
        authenticated: false,
        user: undefined,                   // userData like name, level, ...
        notificationManager: undefined    // contains socket to receive notifications
    }, 
    setUserState: () => {}
});

export default AppContext;

在我的 App 组件中,我为用户实例化一个状态并将其作为值传递给 AppContext.Provider。

// App.tsx

function App() {

  const [userState, setUserState] = useState<UserStateProperties>({
    authenticated: false,
    user: undefined,                         
    notificationManager: undefined
  });

  return (
    <Suspense fallback={'Die Seite lädt...'}>
      <AppContext.Provider value ={{userState, setUserState}}>
        <Router history={createBrowserHistory()}>
          <Switch>
            <Route path='/' exact component={ Home }/>
            <Route path='/auth/forgot' exact component = { Forgot } />
            <Route path='/auth/:type' exact component={ Auth }/>
             // A lot more components
            <Route component={ ErrorPage }/>
          </Switch>
        </Router>
      </AppContext.Provider>
    </Suspense>
  );
}

我的每个组件(例如主页)

// Home.tsx
...
return(
        <Frame current='/'>
            <section className='home-landingPage'>
            ...
        </Frame>
)

包裹在框架组件中

// Frame.tsx

interface FrameProperties {
    children: React.ReactNode | React.ReactNode[],
    current?: string
}

export default function Frame(props: FrameProperties) {
    return (
        <div className='frame-container'>
            <NavigationBar current={ props.current } />
                { props.children }
            <Footer/>
        </div>
    )
}

向组件添加 NavigationBar。 在此 NavigationBar 中,我正在渲染 signin/signup 按钮(如果已验证 == false)或注销按钮、个人资料图片、级别进度(如果已验证 == true)。 为了确保导航栏显示正确的信息,我使用了一个效果钩子,它会更新 userStatus。

//Navigation.tsx

import AppContext from '../../../context/appState';
...

export default function NavigationBar(props: NavigationBarProps) {

    const {userState, setUserState} = useContext(AppContext)
    const updateUser = async () => {
        fetchGetOwnUser().then(response => {
            if(response.status === 200) {
               setUserState({...userState, user: response.data});    // update user
            }
        }).catch(err => {
            console.error(err);
        });
        console.log("USERSTATE AFTTER: ");
        console.log(userState);
    }

    const updateAuthenticationStatus = async () => {
        const accessToken = localStorage.getItem('accessToken');
        if(accessToken) {
            fetchVerifyToken({token: accessToken})
            .then(response => {
                if(response.status == 200){
                    const userId = getTokenPayload(accessToken).sub;
                    setUserState({authenticated: true, user: userState.user, notificationManager: userState.notificationManager || new NotificationManager(userId)}); //update authentication status of user
                }
            })
            .catch(err => {
                 console.error(err);
            });
      console.log("USERSTATE AFTER: ");
      console.log(userState);
   }

   useEffect(() => {
        console.log("USERSTATE BEFORE: ");
        console.log(userState);
        if(userState.authenticated){
            updateUser();
        }else{
            updateAuthenticationStatus();
        }    
    }, []);
}

但是,虽然updateAuthenticationStatus和updateUser执行成功了,但是userState对象并没有改变。控制台显示以下输出。

USERSTATE BEFORE: Object { authenticated: false, user: undefined, notificationManager: undefined }

USERSTATE AFTTER:对象 { 认证:false,用户:未定义,notificationManager:未定义}

提前感谢您的帮助!

您的代码看起来不错,您只是在无用的地方写了日志语句。 fetchVerifyToken 是异步的,因此下一行的日志语句将在 fetchVerifyToken 完成之前 运行,即使您等待承诺,userState 也是本地 const 并且永远不会更改。

您真正关心的是组件使用新值重新呈现,因此将您的 console.log 放在组件主体中以验证它是否重新呈现。例如:

export default function NavigationBar(props: NavigationBarProps) {
    const {userState, setUserState} = useContext(AppContext)
    console.log('rendered with', userState);
    // ...