反应:无法使用 useContext 钩子在 app.js 中设置上下文状态
Posted
技术标签:
【中文标题】反应:无法使用 useContext 钩子在 app.js 中设置上下文状态【英文标题】:React : Unable to set context state in app.js using useContext hook 【发布时间】:2020-10-20 10:18:13 【问题描述】:我无法在我的 app.js 中设置上下文状态,我在其中得到了空值,但可以在子组件中访问它。
我想在用户访问页面时在 app.js 中设置上下文状态,以便我可以在整个应用程序中使用它,例如根据用户是否登录显示不同的标题
请求的沙盒 URL -> https://codesandbox.io/s/quizzical-snyder-2qghj?file=/src/App.js
我关注https://upmostly.com/tutorials/how-to-use-the-usecontext-hook-in-react
app.js
// import installed dependencies
import React, useEffect, useContext from 'react';
import BrowserRouter as Router, Switch, Route from 'react-router-dom';
// import custom contexts
import AuthContext, AuthContextProvider from './contexts/auth/AuthContext';
// import pages
import Homepage from './pages/homepage/Homepage';
// import components
import Footer from './components/footer/Footer';
import Header from './components/header/Header';
export default function App()
const [authState, setAuthState] = useContext(AuthContext);
useEffect(() =>
console.log(authState); // prints **
console.log(setAuthState); // prints *() => *
const token = localStorage.getItem('token');
const tokenIsExpired = parseInt(localStorage.getItem('tokenIsExpired'));
if (!tokenIsExpired && token.length)
setAuthState(
userIsLoggedin: true,
fName: 'test fname',
lName: 'test lname',
userName: 'testname'
);
else
setAuthState(
userIsLoggedin: false,
fName: '',
lName: '',
userName: ''
);
if (tokenIsExpired)
localStorage.setItem('token', '');
, [authState, setAuthState]);
return (
<Router>
<AuthContextProvider value=[authState, setAuthState]>
<div className='App'>
<Header />
<Switch>
<Route exact path='/'>
<Homepage />
</Route>
</Switch>
<Footer />
</div>
</AuthContextProvider>
</Router>
);
AuthContext.js
import React, useState, createContext from 'react';
const AuthContext = createContext([, () => ]);
const AuthContextProvider = (props) =>
const [authState, setAuthState] = useState(
userIsLoggedin: false,
fName: '',
lName: '',
userName: ''
);
return (
<AuthContext.Provider value=[authState, setAuthState]>
props.children
</AuthContext.Provider>
);
;
export AuthContext, AuthContextProvider ;
UseAuthCONtext.js
import useContext from 'react';
import AuthContext from './AuthContext';
const useAuthContext = () =>
const [authState, setAuthState] = useContext(AuthContext);
const login = (loginDetails) =>
setAuthState(
userIsLoggedin: true,
fName: 'test fname',
lName: 'test lname',
userName: 'testname'
);
;
const logout = () =>
setAuthState(
userIsLoggedin: false,
fName: '',
lName: '',
userName: ''
);
;
return login, logout ;
;
export default useAuthContext;
Header.js
// import installed dependencies
import React, useContext, useEffect from 'react';
// import components
import LoggedOutHeader from './logged-out-header/LoggedOutHeader';
import LoggedInHeader from './logged-in-header/LoggedInHeader';
// import custom contexts
import AuthContext from '../../contexts/auth/AuthContext';
const Header = () =>
const [authState, setAuthState] = useContext(AuthContext);
console.log(authState); //prints *userIsLoggedin: false, fName: "", lName: "", userName: ""*
console.log(setAuthState); //prints *ƒ dispatchAction(fiber, queue, action) ...*
const header = authState.isUserLoggedIn ? (
<LoggedInHeader />
) : (
<LoggedOutHeader />
);
return header;
;
export default Header;
【问题讨论】:
规则101永远不要在useEffect的依赖数组中添加setter函数 请创建沙盒并分享 【参考方案1】:您可以在index.js
中使用上下文提供程序。
ReactDOM.render(
<AuthContextProvider>
<App />
</AuthContextProvider>,
document.getElementById('root')
)
【讨论】:
【参考方案2】:您将value
传递给AuthContextProvider
,这似乎是您想要使用的value
,但您没有使用它。
// value not used inside `AuthContextProvider`
<AuthContextProvider value=[authState, setAuthState]>
应该是:
const AuthContextProvider = (props) =>
return (
<AuthContext.Provider value=props.value>
props.children
</AuthContext.Provider>
);
;
【讨论】:
在 app.js 中仍然得到相同的空值 你有可生产的例子吗? How to create a Minimal, Reproducible Example, codesandbox 添加了有问题的沙盒【参考方案3】:您正在使用 App 组件中的上下文,该上下文未包含在 AuthContextProvider 中。在这种情况下,App 组件中的 useContext 调用不会返回提供给 AuthContextProvider 的值,而是会返回提供给 createContext 调用的“默认”值。
您需要将 App 组件中的这些逻辑推迟到 AuthContextProvider 中的子组件。
见createContext api的注释: defaultValue 参数仅在组件树中没有匹配的 Provider 时使用。这有助于在不包装组件的情况下单独测试组件。注意:将 undefined 作为 Provider 值传递不会导致消费组件使用 defaultValue。
【讨论】:
以上是关于反应:无法使用 useContext 钩子在 app.js 中设置上下文状态的主要内容,如果未能解决你的问题,请参考以下文章
如何将 React 钩子(useContext、useEffect)与 Apollo 反应钩子(useQuery)结合起来
使用React useContext hook进行分派调用后,反应状态不会更新
如何测试组件中的react useContext useReducer调度