Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Designing React Hooks prevent react-hooks/exhaustive-deps warning

I am designing a hook to fetch data only when the hooks dependencies change. It works as expected but I receive the linter warnings:

React Hook useEffect was passed a dependency list that is not an array literal. This means we can't statically verify whether you've passed the correct dependencies.

and

React Hook useEffect has missing dependencies: 'data', 'errorHandler', 'route', and 'successHandler'. Either include them or remove the dependency array. If 'successHandler' changes too often, find the parent component that defines it and wrap that definition in useCallback. 

As far as I am aware I do not want all these vars in my dependencies as I don't want to fire this hook when these change, I only want to fire it when the dependencies I pass change.

Question: How can I design useFetch() hook in a way that coincides with the hooks linter standards (if my design pattern is not up to par, please elaborate on how best this should be accomplished).

My useFetch() hook

function useFetch(
    {
        route,
        data = {},
        successHandler,
        errorHandler,
    },
    dependencies = []) {
    const [loading, setLoading] = useState(true);
    useEffect(() => {
        setLoading(true);
        postJson({route}, data)
            .then(
                res => {
                    if(isFunction(successHandler)) successHandler(res);
                },
                ({responseJSON: err}) => {
                    if(isFunction(errorHandler)) {
                        errorHandler(err);
                    } else {
                        notify({text: err.message || messages.saveFailed(), cssClass: 'error'});
                    }
                }
            )
            .finally(() => {
                setLoading(false);
            });
    }, dependencies);
    return loading;
}

Component using useFetch()

function MyComponent({data, selectedReviewId, setField}) {
    const loading = useFetch({
        route: 'foo.fetchData',
        data: {crrType, clientId, programId, userId},
        successHandler: d => setField([], d) // setField() will set data with the value fetched in useFetch() 
    }, [selectedReviewId]);

    return loading ? <SpinnerComponent/> : <div>{data.foo}</div>;
}
like image 443
Miroslav Glamuzina Avatar asked Oct 28 '25 15:10

Miroslav Glamuzina


1 Answers

You have passed dependency as array but on the receiving end, it's essentially a single variable pointing to an array. Lint rule of useEffect() requires that you pass dependencies in square brackets like done in following code.

Now some technical stuff. Remember what's generating the warning. It's the lint which checks code syntactically. It doesn't go into semantics. Semantically, your list of dependencies is correct, as you are passing an array but syntactically, it's not being passed as an array i.e. it's a single variable not passed in square brackets (like this [dependencies]) (which is something lint is looking for). So in order to satisfy lint, you should write:

useEffect(
  () => { // implementation of function },
  [dependencies]
);

Further, as you are sending an array of dependencies, you can also use spread operator, like this:

useEffect(
  () => { // implementation of function },
  [...dependencies]
);

This will spread the array elements inside array operator by Babel transpiler. Lint will also remain quiet.

like image 77
Muhammad Shahbaz Avatar answered Oct 31 '25 05:10

Muhammad Shahbaz



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!