I am using an useEffect inside a Context. I think the useEffect should run after load the page, but it does not work, but if I refresh the page(F5) then it works.
I am new Using React, but I think it should work with the empty array as arg.
This is the Context:
import { createContext, useState, useEffect } from "react"; const PatientContext = createContext(); export const PatientsProvider = (props) => { const {children} = props; const [patients, setPatients] = useState([]); //get the patients from the database useEffect( () => { const url = `${import.meta.env.VITE_BACKEND_URL}/api/patients`; const token = localStorage.getItem("token"); if(!token) return; const getPatients = async () => { try { const response = await fetch(url, { method: 'GET', headers: { 'Content-Type': 'application/json', "Authorization" : `Bearer ${token}` } }); const result = await response.json(); if (!response.ok){ throw new Error(result.msg); } const {createdAt, __v, updatedAt, ...savedPatient} = result; setPatients(result) setLoading(false); } catch (error) { setLoading(false) setAlert({msg: error.message, error1: true}) console.log(error) } } getPatients(); }, [])
EDIT:
Now I realized that the problem is the useEffect render the first time in the login page (before I need it, because I need it after the login page), this is happening because PatientProvider is parent of all the components even Login component, but now I do not know how to set this provider to only “after login components”.
Here is my Routes:
function App() { return ( <BrowserRouter> <AuthProvider> <PatientsProvider> <Routes> <Route path="/" element={< Authlayout />}> <Route index element={ <Login /> } /> <Route path="sign-up" element= {<SignUp />}/> <Route path="forgot-password" element= {<ForgotPassword />}/> <Route path="forgot-password/:token" element= {<ResetPassword />}/> <Route path="confirm-account/:token" element= {<Confirm />}/> </Route> <Route path="/admin" element={<LoginLayout />}> <Route index element={<AdminPatients />} /> <Route path="profile" element= {<Profile />}/> <Route path="change-password" element= {<ChangePass />}/> </Route> </Routes> </PatientsProvider> </AuthProvider> </BrowserRouter> ) }
Advertisement
Answer
It seems like your token is not set by the time the component mounts and calls this useEffect().
I can think of 2 options:
- store your session data in an outer context state and get the token from there. Then you can add
token
as a dependency in useEffect():
// assuming token is stored in context state // and will update const {token} = useAuthContext() useEffect(() => { // ... // will be called every time the token changes }, [token])
- Subscribe to localStorage in this component. react-hookz lib has a nice hook already written, providing it here for simplicity:
import { useLocalStorageValue } from '@react-hookz/web' const PatientsProvider = (props) => { const [token] = useLocalStorageValue('token') useEffect(() => { // do sth with the token }, [token])