skip to Main Content

I want to make a reusable http hook for my project, and use abortController as the clean up function.

import { useState, useEffect } from 'react';

const useHttp = (url = {}, opts = {}) => {
  const [resData, setResData] = useState(null);
  const [error, setError] = useState(null);
  const [isLoading, setIsLoading] = useState(false);
  const [status, setStatus] = useState(null);

  useEffect(() => {
    if (url === '') return;

    const controller = new AbortController();
    const { signal } = controller;

    setIsLoading(true);

    const fetchData = async () => {
      try {
        const response = await fetch(url, {
          method: opts.method || 'GET',
          body: opts.body || undefined,
          headers: opts.headers || {
            'Content-Type': 'application/json',
          },
          credentials: 'include',
          signal,
        });

        const data = await response.json();
        console.log(data);
        const resStatus = response.status;

        // setResData(data);
        setError(null);
        setIsLoading(false);
        setStatus(resStatus);
      } catch (err) {
        // setResData(null);
        setError(err);
        setIsLoading(false);
        setStatus(500);
      }
    };

    fetchData();

    return () => {
      controller.abort();
    };
  }, [url, opts]);

  return { resData, error, isLoading, status };
};

export default useHttp;

I found out that It only happens infinity loop when I set the resData state but I have no idea why.

Because I found a lot of example also set the state of respsonse data inside the hook.

Can someone Point it out to me?

2

Answers


  1. I think the issue is that url and opts default to {}.

    Compared to e.g. strings where "" === "" -> true objects are compared by reference and thus {} === {} -> false. In you case that means that to React url and opts are different on every render and this will cause the useEffect to run on every render.

    As a fix I’d recommend you to remove the default values for url and opts and allow them to be undefined. Since undefined === undefined -> true the useEffect will only run once.

    An alternative that might work if you want to keep the default values is to declare them once, and reuse that value. That way React will notice that the value is the same.

    const urlDefault = {}
    const optsDefault = {}
    const useHttp = (url = urlDefault, opts = optsDefault) => {
    
    Login or Signup to reply.
  2. This is happening because when states will set in this custom hook(useHttp) then the component will re-render where you are using this useHttp hook.

    Then again that component will trigger useHttp hook to re-run and so on
    And that causes the infinity loop.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search