React Context 和 Provider 数据没有按预期传递
Posted
技术标签:
【中文标题】React Context 和 Provider 数据没有按预期传递【英文标题】:React Context and Provider data doesn't get passed down as expected 【发布时间】:2022-01-12 01:12:30 【问题描述】:我正在尝试更新另一个组件正在使用的对象。
我的背景:
import React, Component, createContext from "react";
import jwt from 'jsonwebtoken';
const LOCAL_STORAGE_AUTH_TOKEN = 'authToken';
interface AuthenticatedUser
username?: string;
guildName?: string;
guildId?: string;
interface AuthContextType
authenticated: boolean; // to check if authenticated or not
user: AuthenticatedUser; // store user details
token: string; //jwt token
refreshToken: string; //jwt refresh token
handleAuthentication: (username: string, password: string) => Promise<void>; // handle login process
logout: () => Promise<void>; // log out the user
export const AuthContext = createContext<AuthContextType>(
authenticated: false, // to check if authenticated or not
user: , // store all the user details
token: '', // store all the user details
refreshToken: '', //jwt refresh token
handleAuthentication: (username: string, password: string): Promise<void> =>
Promise.resolve(), // handle login process
logout: (): Promise<void> => Promise.resolve(), // logout the user
);
AuthContext.displayName = 'AuthContext';
export class AuthProvider extends Component
state =
authenticated:false,
user: ,
token:'',
refreshToken:''
;
constructor(props: any)
super(props);
const token = window.localStorage.getItem(LOCAL_STORAGE_AUTH_TOKEN) || '';
const jwtData = jwt.decode(token);
let user = ;
let authenticated = false;
let refreshToken = '';
if(jwtData && typeof jwtData !== 'string')
authenticated = true;
user =
username: jwtData.data?.username || '',
// TODO: Add the other sources too
this.state =
authenticated,
user,
token,
refreshToken
handleAuthentication = async (username: string, password: string):Promise<void> =>
fetch(process.env.REACT_APP_API_ENDPOINT + "users/login",
method:"POST",
headers: "Content-Type": "application/json" ,
body: JSON.stringify(username:username, password:password)
)
.then(response => response.json())
.then((data) =>
/*
This data is coming back correctly
*/
const user =
username: data?.user.username,
guildName: data?.user.guild_information[0].guildName,
guildId: "123123"
this.setState(
authenticated: true,
user: user,
token: data?.token,
refreshToken: data?.refreshToken
)
window.localStorage.setItem(LOCAL_STORAGE_AUTH_TOKEN, data?.token)
//TODO: Also save token in localstorage
)
.catch((err) =>
console.log(err)
)
logout = async ():Promise<void> =>
//TODO: Log out the current user
render()
const authProviderValue =
...this.state,
handleAuthentication: this.handleAuthentication,
logout: this.logout
return (
<AuthContext.Provider value=authProviderValue>
this.props.children
</AuthContext.Provider>
)
以及我使用它的 App 组件:
import React, useContext from "react";
import useStyles from "./style";
import AuthContext, AuthProvider from "../../context/UserContext";
import RoutesProvider from "./Routes";
import Login from "../Login";
export default function App()
const classes = useStyles();
const user = useContext(AuthContext)
return (
<AuthProvider>
typeof user.username !== "undefined" ? (
<div className=classes.content>
<RoutesProvider />
</div>
):(
<Login />
)
</AuthProvider>
)
还按照建议将 App 组件包装在 AuthProvider 中:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';
import SnackbarProvider from 'notistack';
import AuthProvider from "./context/UserContext";
import './styles/index.css'
ReactDOM.render(
<React.StrictMode>
<AuthProvider>
<SnackbarProvider maxSnack=3>
<App />
</SnackbarProvider>
</AuthProvider>
</React.StrictMode>,
document.getElementById('root')
);
如果我在 AuthContext 中更改它,它确实会采用初始值。但是更新后它不会在 App 组件中更新。我有点困惑为什么这不能按预期工作。如果有人知道是什么原因造成的(或者我做错了),请告诉我。目前调试 5 小时...
【问题讨论】:
【参考方案1】:如果我正确理解了您的问题,您是在问:
“为什么当你的 handleAuthentication 方法成功时你的用户常量没有更新”
答案是因为您在提供者之外初始化用户常量。
在 index.tsx 中使用 AuthProvider,而不是像这样的 App 组件:
<AuthProvider>
<App />
</AuthProvider>
或者将您的上下文逻辑转移到子组件中
【讨论】:
我刚刚添加了。这确实适用于 handleAuthentication 方法,但只有在刷新之后才能从 localStorage 获取 authToken。 从您的 App 组件中删除身份验证提供程序 你真是天赐良机。这完美无缺。我也看到出了什么问题并现在理解它,至少在某种程度上:D 非常感谢您以上是关于React Context 和 Provider 数据没有按预期传递的主要内容,如果未能解决你的问题,请参考以下文章
React Context 和 Provider 数据没有按预期传递
使用React Context进行状态管理(五)Provider与Consumer匹配
React中的connect使用(Provider+Consumer例子 以及 contextType+this.context例子)