javascript - 为什么 useContext 只在子组件/函数中更新?
问题描述
大家好,我正在开发一个 React 应用程序,我正在使用 React-Hooks 。我使用包含 userId 和 token 的 creatContext 创建了一个新的上下文。我将导航栏设置为在用户登录时更改,并且我还将在用户登录时从 AuthPage 重定向到另一个页面。问题是当我登录时,导航栏实际上发生了变化,但它并没有将我重定向到它应该在的位置,即使我登录了。为什么不更新 AuthPage?我也尝试使用
我创建上下文的文件:
import React ,{ createContext} from 'react' ;
const context= createContext({
userId:null,
token: null ,
login: (userId, token , tokenExpiration)=> {} ,
logout: ()=>{}
});
export default context ;
应用程序.js:
import './App.css';
import AuthPage from './pages/AuthPage'
import {BrowserRouter, Route , Redirect , Switch} from 'react-router-dom'
import EventsPage from './pages/EventsPage';
import BookingsPage from './pages/BookingsPage';
import MainNavigation from './components/Navigation/MainNavigation'
import AuthContext from './context/auth-context';
import { useState , useContext, useMemo } from 'react';
function App() {
const context = useContext(AuthContext);
const[token , setToken] =useState(null) ;
const[userId , setUserId] =useState(null);
const login=(token,userId , tokenExpiration)=>{
setToken(token) ;
setUserId(userId);
}
const logout=()=>{
setToken(null);
setUserId(null);
}
const updateAndRender =useMemo(() => ( {
token:token ,
userId:userId ,
login:login,
logout:logout
}
), [token , userId , login]);
return (
<BrowserRouter>
<AuthContext.Provider
value={updateAndRender}
>
<MainNavigation/>
<main className="main-content">
<Switch>
{context.token && <Redirect from="/auth" to="/bookings" exact /> }
{context.token && <Redirect from="/auth" to="/events" exact /> }
{!context.token && <Redirect from="/" to="/auth" exact />}
{!context.token && <Redirect from="/bookings" to="/auth" exact />}
{!context.token && <Route path="/auth" component={AuthPage} />}
<Route path="/events" component={EventsPage} />
{ <Route path="/bookings" component={BookingsPage} />}
</Switch>
</main>
</AuthContext.Provider>
</BrowserRouter>
);
}
export default App;
认证页面:
import React , {useContext, useState , useEffect} from 'react';
import './AuthPage.css';
import AuthContext from '../context/auth-context';
export default function Authpage(props) {
const [email , setEmail]=useState(" ");
const [password , setPassword]=useState(" ");
const [isLogin , setIsLogin]=useState(true);
const context = useContext(AuthContext);
const swithmodeHandler=()=> { setIsLogin(!isLogin)}
const submitHandler=async (e)=>{
e.preventDefault();
let requestBody ={
query:
`
query{
login(email:"${email}" , password:"${password}")
{
userId
token
tokenExpiration
}
}
`
}
if(isLogin){
requestBody={
query:`
mutation{
createUser(userInput:{email:"${email}" , password:"${password}" })
{
_id
email
}
}`
}
}
try {
const requestToGql = await fetch('http://localhost:3001/graphql' , {
method:'POST' ,
body:JSON.stringify(requestBody) ,
headers:{
'Content-Type': 'application/json'
}})
if(requestToGql.status!==200 && requestToGql.status!==201){
throw new Error("Failed creating user");
}
const resData=await requestToGql.json() ;
if((Object.keys(resData.data.login) !==0) || resData.data.login.token){
context.login(resData.data.login.userId,
resData.data.login.token,
resData.data.login.tokenExpiration
) ;
}
return resData ;
} catch (error) {
console.log(error)
}
}
return <form className="auth-form" onSubmit={submitHandler}>
<div className="form-control"> <label htmlFor="email"> Email</label>
<input value={email} type="email" id="email" onChange={e=>setEmail(e.target.value)}/>
</div>
<div className="form-control">
<label htmlFor="password"> Password</label>
<input value={password} type="password" id="password" onChange={e=>setPassword(e.target.value)}/>
</div>
<div className="form-actions">
<button type="submit"> Submit</button>
<button onClick={swithmodeHandler} type="button"> {isLogin? "Signup" : "Login"}</button>
</div>
</form>
}
导航栏组件:
import React , {useContext} from 'react' ;
import {NavLink} from 'react-router-dom'
import './MainNavigation.css'
import AuthContext from '../../context/auth-context'
export default function MainNavigation(props){
const context = useContext(AuthContext) ;
return(
<header className="main-navigation">
<div className="main-navigation_logo">
<h1> Yul's Gym</h1>
</div>
<nav className="main-navigation_items">
<ul>
{ !context.token &&
<li>
<NavLink to="/auth"> Authenticate</NavLink>
</li>
}
<li>
<NavLink to="/events"> Events</NavLink>
</li>
{ context.token &&
<li>
<NavLink to="/bookings"> Bookings</NavLink>
</li>
}
</ul>
</nav>
</header>
)
}
解决方案
你不能在你初始化的里面context
使用任何东西component
context
对于您的情况,您应该创建另一个component
例如router
并使用context
内部并初始化App
组件中的上下文
布局.js
import AuthPage from './pages/AuthPage'
import {BrowserRouter, Route , Redirect , Switch} from 'react-router-dom'
import EventsPage from './pages/EventsPage';
import BookingsPage from './pages/BookingsPage';
import MainNavigation from './components/Navigation/MainNavigation'
import AuthContext from './context/auth-context';
import { useState , useContext, useMemo } from 'react';
function Layout() {
const context = useContext(AuthContext);
const[token , setToken] =useState(null) ;
const[userId , setUserId] =useState(null);
const login=(token,userId , tokenExpiration)=>{
setToken(token) ;
setUserId(userId);
}
const logout=()=>{
setToken(null);
setUserId(null);
}
const updateAndRender =useMemo(() => ( {
token:token ,
userId:userId ,
login:login,
logout:logout
}
), [token , userId , login]);
return (
<BrowserRouter>
<MainNavigation/>
<main className="main-content">
<Switch>
{context.token && <Redirect from="/auth" to="/bookings" exact /> }
{context.token && <Redirect from="/auth" to="/events" exact /> }
{!context.token && <Redirect from="/" to="/auth" exact />}
{!context.token && <Redirect from="/bookings" to="/auth" exact />}
{!context.token && <Route path="/auth" component={AuthPage} />}
<Route path="/events" component={EventsPage} />
{ <Route path="/bookings" component={BookingsPage} />}
</Switch>
</main>
</BrowserRouter>
);
}
export default Layout;
应用程序.js
import './App.css';
import Layout from '../Layout/Layout.js'
import AuthContext from './context/auth-context';
function App() {
return (
<AuthContext.Provider
value={updateAndRender}
>
<Layout />
</AuthContext.Provider>
);
}
export default App;
推荐阅读
- excel - Office calc - 周末的条件格式
- swift - 命令 MergeSwiftModule 失败,退出代码为非零
- python - Python - 有没有一种聪明的方法在数组的某些索引之间加 1?
- ruby-on-rails-4 - 过滤器上有多个直通连接
- java - Android Google 登录返回 RESULT_CANCELLED
- javascript - 在mysql中存储来自重复表单字段的多维数组
- appveyor - 什么是最少可用的 Python 3.5 版本以及在哪里可以找到它?
- python - 有没有办法从字典中创建 url?
- c - 内存分配和getline
- python - SWIG 包装器未声明(在此函数中首次使用)