skip to Main Content

I’m trying to make reusable GET and POST requests, but I’m getting error Invalid hook call when setting the data state in the reusable fetch request component. I’ve just learnt that we can only use hooks in React components, so how can I make that functionality reusable?

import axios from "axios";
import { useContext, useEffect, useState } from "react";
import AuthContext from "../../context/Auth-context/AuthContext";
import { useNavigate } from "react-router-dom";



export const POST = (url, body, credentials) => {
  const [data, setData] = useState([]);
  const [isLoaded, setIsLoaded] = useState(false);
  const [error, setError] = useState(null);
  const { dispatch } = useContext(AuthContext);
  const navigate = useNavigate();


  useEffect(() => {
    const fetchData = () => {
      axios
        .post(url, body, { withCredentials: credentials })
        .then((response) => {
          setIsLoaded(true);
          setData(response.data);
        })
        .catch((error) => {
          if (error.status === 401) {
            dispatch({ type: "LOGOUT" });
            navigate("/login");
            return;
          }
          setError(error);
        });
    };
    fetchData();
  }, [url, credentials, dispatch, navigate, body]);

  return { error, isLoaded, data };
};
  const approve = async (id) => {
    const { data, error, isLoaded } = POST(
      "http://localhost:8000/api/new-users",
      id,
      true
    );
    if (error) {
      return (
          <Error/>
      );
    }
    if (!isLoaded) {
      return (
          <Loader/>
      );
    }

    console.log(data);

  };

2

Answers


  1. Rename the POST into ‘usePost’ and check.

    You must follow these naming conventions:

    React component names must start with a capital letter, like StatusBar and SaveButton. React components also need to return something that React knows how to display, like a piece of JSX.

    Hook names must start with use followed by a capital letter, like useState (built-in) or useOnlineStatus (custom, like earlier on the page). Hooks may return arbitrary values.

    https://react.dev/learn/reusing-logic-with-custom-hooks#hook-names-always-start-with-use

    Login or Signup to reply.
  2. The code is breaking React’s Rules of Hooks. React hooks, i.e. useState, useNavigate, etc, can only be called in React functions and custom React hooks, and POST is neither of these. The trivial solution would be to simply rename POST to be a valid React hook, e.g. using the "use-" prefix on the identifier. The issue then is that you would be calling usePost in a callback which again breaks React’s Rules of Hooks.

    I suggest a refactor to return a "trigger" function that handles the fetch (instead of useEffect) which can be called in a callback.

    Example:

    export const usePost = (url, credentials) => {
      const [data, setData] = useState([]);
      const [isLoaded, setIsLoaded] = useState(false);
      const [error, setError] = useState(null);
      const { dispatch } = useContext(AuthContext);
      const navigate = useNavigate();
    
      const trigger = useCallback((body) => {
        return axios
          .post(url, body, { withCredentials: credentials })
          .then((response) => {
            setData(response.data);
          })
          .catch((error) => {
            if (error.status === 401) {
              dispatch({ type: "LOGOUT" });
              navigate("/login");
              return;
            }
            setError(error);
          })
          .finally(() => {
            setIsLoaded(true);
          });
      }, [url, credentials, dispatch, navigate]);
    
      return { error, isLoaded, data, trigger };
    };
    

    Usage:

    const { data, error, isLoaded, trigger } = usePost(
      "http://localhost:8000/api/new-users",
      true
    );
    
    ...
    
    const approve = async (id) => {
      trigger(id);
    }
    
    ...
    
    if (error) {
      return <Error />;
    }
    
    if (!isLoaded) {
      return <Loader />;
    }
    
    ...
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search