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:
JavaScript
x
50
50
1
import { createContext, useState, useEffect } from "react";
2
3
const PatientContext = createContext();
4
5
export const PatientsProvider = (props) => {
6
const {children} = props;
7
8
const [patients, setPatients] = useState([]);
9
10
11
//get the patients from the database
12
useEffect( () => {
13
const url = `${import.meta.env.VITE_BACKEND_URL}/api/patients`;
14
const token = localStorage.getItem("token");
15
16
if(!token) return;
17
18
const getPatients = async () => {
19
try {
20
const response = await fetch(url, {
21
method: 'GET',
22
headers: {
23
'Content-Type': 'application/json',
24
"Authorization" : `Bearer ${token}`
25
}
26
});
27
28
const result = await response.json();
29
30
if (!response.ok){
31
throw new Error(result.msg);
32
}
33
34
const {createdAt, __v, updatedAt, ...savedPatient} = result;
35
36
setPatients(result)
37
setLoading(false);
38
39
40
} catch (error) {
41
setLoading(false)
42
setAlert({msg: error.message, error1: true})
43
console.log(error)
44
45
}
46
}
47
48
getPatients();
49
}, [])
50
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:
JavaScript
1
26
26
1
function App() {
2
return (
3
<BrowserRouter>
4
<AuthProvider>
5
<PatientsProvider>
6
<Routes>
7
<Route path="/" element={< Authlayout />}>
8
<Route index element={ <Login /> } />
9
<Route path="sign-up" element= {<SignUp />}/>
10
<Route path="forgot-password" element= {<ForgotPassword />}/>
11
<Route path="forgot-password/:token" element= {<ResetPassword />}/>
12
<Route path="confirm-account/:token" element= {<Confirm />}/>
13
</Route>
14
15
<Route path="/admin" element={<LoginLayout />}>
16
<Route index element={<AdminPatients />} />
17
<Route path="profile" element= {<Profile />}/>
18
<Route path="change-password" element= {<ChangePass />}/>
19
</Route>
20
</Routes>
21
</PatientsProvider>
22
</AuthProvider>
23
</BrowserRouter>
24
)
25
}
26
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():
JavaScript
1
8
1
// assuming token is stored in context state
2
// and will update
3
const {token} = useAuthContext()
4
useEffect(() => {
5
// ...
6
// will be called every time the token changes
7
}, [token])
8
- Subscribe to localStorage in this component. react-hookz lib has a nice hook already written, providing it here for simplicity:
JavaScript
1
9
1
import { useLocalStorageValue } from '@react-hookz/web'
2
3
const PatientsProvider = (props) => {
4
const [token] = useLocalStorageValue('token')
5
6
useEffect(() => {
7
// do sth with the token
8
}, [token])
9