我有一个客户端在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)
// Home.tsx
...
return(
<Frame current='/'>
<section className='home-landingPage'>
...
</Frame>
)
被封装在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添加到组件。在这个导航栏,我渲染的东西,如登录/注册按钮(在情况下authenticated == false)或签出按钮,个人资料图片,水平进展(在情况下authenticated == 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 after: Object {authenticated: false, user: undefined, notificationManager: undefined}
提前感谢您的帮助!
你的代码看起来很好,你只是把你的日志语句写在了无用的地方。fetchVerifyToken是异步的,所以下一行的日志语句将在fetchVerifyToken完成之前运行,即使你等待承诺,userState是一个本地const
,永远不会改变。
您真正关心的是组件呈现新值,因此将console.log放在组件的主体中以验证它是否呈现。例如:
export default function NavigationBar(props: NavigationBarProps) {
const {userState, setUserState} = useContext(AppContext)
console.log('rendered with', userState);
// ...