[英]why useContext updated only in children components/functions?
大家好,我正在開發一個 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;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.