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);
// ...
我有一个用 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);
// ...