'How to trigger useEffect before render?

I am using axios to fetch data and then want to render the component. For that, I have loading which gets set to true when fetching and to false when all the data has come. But I am getting error. Is there a way to trigger useEffect before rendering of component ?

Following is the code:

GithubReducer.js

import {
  SET_USERS,
  CLEAR_USERS,
  SET_LOADING,
  SET_USER,
  CLEAR_USER,
} from "../types";

const GithubReducer = (state, action) => {
  switch (action.type) {
    case SET_USERS: {
      return { ...state, users: action.payload };
    }

    case CLEAR_USERS: {
      return { ...state, users: [] };
    }

    case SET_LOADING: {
      return { ...state, loading: action.payload };
    }

    case SET_USER: {
      return { ...state, user: action.payload };
    }

    case CLEAR_USER: {
      return { ...state, user: null };
    }

    default:
      return state;
  }
};

export default GithubReducer;

GithubState.js

import React, { useReducer } from "react";
import axios from "axios";

import {
  SET_USERS,
  CLEAR_USERS,
  SET_LOADING,
  SET_USER,
  CLEAR_USER,
} from "../types";

import GithubReducer from "./GithubReducer";
import GithubContext from "./GithubContext";

const GithubState = (props) => {
  const initialState = {
    loading: false,
    users: [],
    user: null,
  };

  const [state, dispatch] = useReducer(GithubReducer, initialState);

  const setLoading = (val) => dispatch({ type: SET_LOADING, payload: val });

  const getGithubUsers = async () => {
    setLoading(true);
    dispatch({ type: CLEAR_USER });

    const res = await axios.get(`https://api.github.com/users`);

    dispatch({
      type: SET_USERS,
      payload: res.data,
    });

    setLoading(false);
  };

  const clearUsers = () => {
    dispatch({ type: CLEAR_USERS });
  };

  const searchUsersWithName = async (username) => {
    setLoading(true);

    const res = await axios.get(
      `https://api.github.com/search/users?q=${username}`
    );

    dispatch({ type: SET_USERS, payload: res.data.items });
    setLoading(false);
  };

  const fetchGithubUserProfile = async (username) => {
    setLoading(true);

    const res = await axios.get(`https://api.github.com/users/${username}`);

    dispatch({ type: SET_USER, payload: res.data });
    setLoading(false);
  };

  return (
    <GithubContext.Provider
      value={{
        getGithubUsers,
        clearUsers,
        searchUsersWithName,
        fetchGithubUserProfile,
        users: state.users,
        loading: state.loading,
        user: state.user,
      }}
    >
      {props.children}
    </GithubContext.Provider>
  );
};

export default GithubState;

User.js

import React, { useContext, useEffect } from "react";
import { useParams } from "react-router-dom";

import GithubContext from "../../context/github/GithubContext";
import Spinner from "../layout/Spinner";

const User = () => {
  const { fetchGithubUserProfile, user, loading } = useContext(GithubContext);
  const { username } = useParams();

  useEffect(() => {
    fetchGithubUserProfile(username);
    // eslint-disable-next-line
  }, []);

  if (loading) return <Spinner />;
  else {
    return (
      <div className="user">
        <button>Go Back</button>
        <section className="about">{user.login}</section>
      </div>
    );
  }
};

export default User;

And, this is the error I am getting:

TypeError: Cannot read properties of null (reading 'login')
User
D:/anubh/Desktop/github-finder/src/components/users/User.js:21
  18 |   return (
  19 |     <div className="user">
  20 |       <button>Go Back</button>
> 21 |       <section className="about">{user.login}</section>
     | ^  22 |     </div>
  23 |   );
  24 | }


Solution 1:[1]

Very simple. You can't. useEffect runs after componentDidMount, or after the JSX has been rendered.

Here is a solution. Render your JSX conditionally depending on state, which you can set once your data is retrieved.

return (
   {data ? <MyComponent /> : null}
) 

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Arcanus