Skip to content
Advertisement

UseEffect only works after refresh the page

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:

  1. 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])
  1. 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])
User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement