Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React hooks with async fetch

I'm new to React hooks, but I'm trying to use a useEffect with a useCallback, but getting the notorious React Hook "useList" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function react-hooks/rules-of-hooks error.

This file holds the makeRequest:

function useConnections = () => {
    const makeRequest = React.useCallback(async (props) => {
        // Determine base url, determine headers here
        const response = fetch(url, options);
        
        return response;
    }

    return { makeRequest };
}

This file is my useListProvider:

function useListProvider = () => {
    const { makeRequest } = useConnections();

    const useList = React.useCallback(async (props) => {
        // makerequest is just a wrapper for fetch with a bunch of needed headers.
        const response = await makeRequest(props);

        return { body: response.body };
    }

    return { useList };
}

This is the rendered page:

function MainPage() {
    const [isBusy, setIsBusy] = React.useStore(false);
    const { useList } = useListProvider();

    React.useEffect(() => {
        if (!isBusy) { useList(); setIsBusy(false); } // ERROR HERE!
    }, [useList]);

    return (
        <React.Fragment>
            IsBusy: {isBusy}
        </React.Fragment>
    );
}

Maybe I'm not getting it, but I only want to grab the useList data when the state says it's not busy. However, doing it this way, I get the error listed above. I understand I can't think of this the same way as Component classes, but how would you approach single and multiple renders from a callback?

I'm not entirely sure what is happening here because I'm doing something similar in the useConnections, etc. and not getting the same error?

like image 529
Sean Avatar asked Sep 06 '25 03:09

Sean


1 Answers

The lint rule for hooks assumes that things which start with "use" are hooks. Thus it thinks that useList is a hook and trying to enforce the rules of hooks on it. But it's not actually a hook, it's just a normal function, so you just need to give it a different name and the lint rule will be satisfied.

function useListProvider = () => {
    const { makeRequest } = useConnections();

    const callback = React.useCallback(async (props) => {
        const response = await makeRequest(props);

        return { body: response.body };
    }, [makeRequest])

    return { callback };
}

// elsewhere:

const { callback } = useListProvider();

React.useEffect(() => {
    if (!isBusy) { 
      callback(); 
      setIsBusy(false);
    }
}, [callback]);

Why is it not a hook? Well, a hook is either one of the built in hooks, or a function that calls one of the built in hooks. Your callback doesn't meet those criteria. It was created by useCallback, but that just means it's a memoized function, not a hook.

like image 64
Nicholas Tower Avatar answered Sep 08 '25 00:09

Nicholas Tower