Search code examples
reactjsasynchronousreact-hooksreact-contextuse-effect

asynchronous context with useEffect in React


im trying to create an api request with the header value, that is received from a context component. However, as soon as the page component is loaded, it throws an Cannot read property '_id' of null exception. Is there a way to run the useEffect function, as soon as the context is loaded?

main component:

import React, { useState, useEffect, useContext } from "react";
import "./overview.scss";

/* COMPONENTS */;
import axios from 'axios';
import { GlobalContext } from '../../components/context/global';

const Overview = () => {
  const [bookings, setBookings] = useState([]);
  const [loaded, setLoaded] = useState(false);

  const [user, setUser] = useContext(GlobalContext);

  useEffect(() => {
      axios
      .get(`/api/v1/bookings/user/${user._id}`)
      .then(res => setBookings(res.data))
      .catch(err => console.log(err))
      .finally(() => setLoaded(true));
  }, [user]);

context component:

import React, {useState, useEffect, createContext} from 'react';
import jwt from 'jsonwebtoken';

/* GLOBAL VARIABLES (CLIENT) */
export const GlobalContext = createContext();

export const GlobalProvider = props => {

    /* ENVIRONMENT API URL */
    const [user, setUser] = useState([]);

    useEffect(() => {
        const getSession = async () => {
            const user = await sessionStorage.getItem('authorization');
            setUser(jwt.decode(user));
    }
    getSession();
    }, [])

    return (
        <GlobalContext.Provider value={[user, setUser]}>
            {props.children}
        </GlobalContext.Provider>
    );
};

Solution

  • The issue here is useEffect is running on mount, and you don't have a user yet. You just need to protect against this scenario

    useEffect(() => {
      if (!user) return;
    
      // use user._id
    },[user])
    

    Naturally, when the Context fetches the user it should force a re-render of your component, and naturally useEffect should re-run as the dependency has changed.