почему useContext обновляется только в дочерних компонентах / функциях?

#javascript #reactjs #react-hooks

#javascript #reactjs #реагирующие хуки

Вопрос:

Привет, ребята, итак, я работаю над приложением React и использую React-хуки. Я создал новый контекст с помощью creatContext, который содержит идентификатор пользователя и токен. Я настраиваю навигационную панель на изменение при регистрации пользователя, а также устанавливаю перенаправление со страницы авторизации на другую страницу при регистрации пользователя. Проблема в том, что когда я выполняю вход в систему, панель навигации фактически меняется, но она не перенаправляет меня туда, где она должна быть, даже если я вошел в систему. Почему он не обновляет страницу авторизации? Я также пытался использовать

Файл, в котором я создаю контекст :

 
import React ,{  createContext} from 'react' ;


 const context= createContext({
    userId:null,
    token: null ,
    login: (userId, token , tokenExpiration)=> {} , 
    logout: ()=>{} 
});

export default context ;
 

App.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 amp;amp; <Redirect from="/auth" to="/bookings" exact /> }

      {context.token amp;amp; <Redirect from="/auth" to="/events" exact /> }
    {!context.token amp;amp; <Redirect from="/" to="/auth" exact />}
    {!context.token amp;amp; <Redirect from="/bookings" to="/auth" exact />}
    
   {!context.token amp;amp; <Route path="/auth" component={AuthPage} />}
   <Route path="/events" component={EventsPage} />
   { <Route path="/bookings" component={BookingsPage} />}



      </Switch>
      </main>
      </AuthContext.Provider>

    </BrowserRouter>
  );
}

export default App;

 

AuthPage:

 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 amp;amp; 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 amp;amp;
             <li>
             <NavLink to="/auth"> Authenticate</NavLink>
         </li>
        }
       
        <li>
            <NavLink to="/events"> Events</NavLink>
        </li>
        { context.token amp;amp;
        
            <li>
            <NavLink to="/bookings"> Bookings</NavLink>
        </li>
        }
        
    </ul>
    </nav>
    </header>
    )
}

 

Ответ №1:

вы не можете использовать что-либо context внутри component того, что вы инициализируете context в

для вашего случая здесь вы должны создать другой component , например router , и использовать context inside и инициализировать контекст в App компоненте

Layout.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 amp;amp; <Redirect from="/auth" to="/bookings" exact /> }

      {context.token amp;amp; <Redirect from="/auth" to="/events" exact /> }
    {!context.token amp;amp; <Redirect from="/" to="/auth" exact />}
    {!context.token amp;amp; <Redirect from="/bookings" to="/auth" exact />}
    
   {!context.token amp;amp; <Route path="/auth" component={AuthPage} />}
   <Route path="/events" component={EventsPage} />
   { <Route path="/bookings" component={BookingsPage} />}



      </Switch>
      </main>
      

    </BrowserRouter>
  );
}

export default Layout;
 

App.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;
 

Комментарии:

1. Спасибо. Я переместил код в Layout.js но сохранил методы входа в систему, выхода из системы, обновления и обновления на App.js досье . Теперь это работает, спасибо.