0

I have infinity loop when using custom hook and reducer in React Hook. Custom hook has been infinity loop when moving dispatch setLoading into async function. But when I calling dispatch action out of async function scope, I have related issue with dispatch action. setLoading(false) will called before async function has been completed. Please help me clarify it

That is my code

reducer:


   import { SET_ERROR, SET_LOADING } from "./common.type";
   
   export const commonInitial = {
     isLoading: false,
     isError: {
       message: "",
       status: "",
     },
   };
   
   const commonReducer = (state: any, action: any) => {
     switch (action.type) {
       case SET_LOADING:
         return { ...state, isLoading: action.payload };
       case SET_ERROR:
         return { ...state, isError: action.payload };
       default:
         return { ...state };
     }
   };
   
   export default commonReducer;

useFetch (custom hook)


     export const useFetch = (url: string) => {
      const [response, setResponse] = useState([]);
      const [error, setErr] = useState({ message: "", status: "" });
      //fetching state handler
      const { dispatch } = useContext(CommonContext);
    
      useEffect(() => {
        const fetchDataFromUrl = async () => {
          //show loading
          dispatch(setLoading(true));
          try {
            const { data } = await axios.get(url);
            setResponse(data);
            dispatch(setLoading(false));
          } catch (err: any) {
            //handle error
            dispatch(setLoading(false));
            setErr(err);
          }
        };
        fetchDataFromUrl();
      }, [url]);
    
      useEffect(() => {
        dispatch(setError({ message: error.message }));
      }, [error]);
    
      return [response];
    }; 

hook called


     // using custom hook fetch data
      const [data] = useFetch("https://jsonplaceholder.typicode.com/posts");
      
      return (
        <div>
          <ul>
            {!!data?.length &&
              data.map((item: Post) => {
                return (
                  <div key={item.id}>
                    <Link to={`/post/${item.id}`}>Moves to Post {item.id}</Link>
                  </div>
                );
              })}
          </ul>
        </div>
      );
    };
    
    export default DemoHookA;

Trung Phan
  • 1
  • 1
  • 1

1 Answers1

0

I am not sure, but the issue could be because of useEffect hook. As per React 18 in invoked multiple types. For getting rid of this rendering issue, you can create a ref that would check if the component is mounted or not and updating the ref once it is mounted.

You could achive this by following way.

import React, {
  useEffect,
  useRef
} from 'react';

function YourComponent() {
  const isRendered = useRef(false);

  // UseEffect
  useEffect(() => {
    if (!isRendered.current) {
      // Your code goes here...
    }

    return () => {
      // Update isRendered
      isRendered.current = true;
    }
  })
}

export default YourComponent;

Put all the code that you have inside useEffect inside the if condition.

Hope it will work for you.

Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
Sachin Som
  • 1,005
  • 3
  • 8