Home > OS >  Cancel fetch with continue request in a custom hook
Cancel fetch with continue request in a custom hook

Time:01-06

I have created a custom hook to fetch data. In that hook I have an async function looking something like this:

const useData = () => {
    const [enabled, setEnabled] = useState(true);
    const [data, setData] = useState(false);
    const fetchData = async () => {
        const response = await fetch();
        const data = await response.json();

        while (data.continue && enabled) {
            response = await fetch(data.requestId);
            data = await response.json();
        }
    };

    useEffect(() => {
        console.log(enabled);
    }, [enabled]);

    return { data, setEnabled };
};

When I call setEnabled(false) from a component it's set to false when the useEffect logs it but it continues to be true in the fetchData function and it never cancels the fetch which I was expecting.

CodePudding user response:

This is because the fetchData callback function "captures" the state of the data variable when it is first called, and it doesn't know about the new value of data when you change it (this is known in React as stale closures). To fix this, you have to use the useRef hook instead:

const useData = () => {
    const [enabled, setEnabled] = useState(true);
    const [data, setData] = useState(false);
    const isCancelled = useRef(false);
    const fetchData = async () => {
        const response = await fetch();
        const data = await response.json();

        while (data.continue && !isCancelled.current) {
            response = await fetch(data.requestId);
            data = await response.json();
        }
    };

    useEffect(() => {
        isCancelled.current = !enabled;
    }, [enabled]);

    return { data, setEnabled };
};
  • Related