Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom hooks with dependency lists and eslint-plugin-react-hooks

I have a question regarding eslint-plugin-react-hooks.

I wanted to reduce the boilerplate code of doing a API call and storing the result into state so I created a custom hook:

export const loading = Symbol('Api Loading');
export const responseError = Symbol('Api Error');

export function useApi<T>(
    apiCall: () => CancelablePromise<T>,
    deps: DependencyList
): T | (typeof loading) | (typeof responseError) {
    const [response, setResponse] = useState<T | (typeof loading) | (typeof responseError)>(loading);
    useEffect(() => {
        const cancelablePromise = apiCall();
        cancelablePromise.promise
            .then(r => setResponse(r))
            .catch(e => {
                console.error(e);
                setResponse(responseError);
            });
        return () => cancelablePromise.cancel();
    }, deps); // React Hook useEffect has a missing dependency: 'apiCall'. Either include it or remove the dependency array. If 'apiCall' changes too often, find the parent component that defines it and wrap that definition in useCallback (react-hooks/exhaustive-deps)
    return response;
}

Now the custom hook works great but the eslint-plugin-react-hooks not so much. The warning in my code is not a big problem. I know i can silence this warning by adding a comment:

// eslint-disable-next-line react-hooks/exhaustive-deps

The problem is that one of the custom hook arguments is a dependency list and eslint-plugin-react-hooks dose not detect missing dependencies on it. How do I make eslint-plugin-react-hooks correctly detect dependency list problems for my custom hook? Is it even possible to have such detection for custom hooks?

like image 940
ParkourGrip Avatar asked Feb 06 '20 14:02

ParkourGrip


2 Answers

The react-hooks/exhaustive-deps rule allows you to check your custom hooks. From the Advanced Configuration options:

exhaustive-deps can be configured to validate dependencies of custom Hooks with the additionalHooks option. This option accepts a regex to match the names of custom Hooks that have dependencies.

{   
  "rules": {
    // ...
    "react-hooks/exhaustive-deps": ["warn", {
      "additionalHooks": "(useMyCustomHook|useMyOtherCustomHook)"
    }]   
  }
} 

In your .eslintrc file, add the following entry in the "rules" config:

'react-hooks/exhaustive-deps': ['warn', {
      'additionalHooks': '(useApi)'
    }],

Then you should be able to call your hook and see the linter warning and use the Quick Fix option.

enter image description here

like image 130
Vinnie Avatar answered Sep 30 '22 14:09

Vinnie


Looks like the dependency lists as arguments in custom hooks are not supported in eslint-plugin-react-hooks (as far as i know). There is a workaround with useCallback as dangerismycat suggested.

So instead of doing:

const apiResult = useApi(() => apiCall(a, b, c), [a, b, c]);

The same functionality can be achieved without the custom hook having a dependency list argument:

const callback = useCallback(() => apiCall(a, b, c), [a, b, c]);
const apiResult = useApi(callback);

While its a shame that it introduces a bit more boilerplate and the code is a bit harder to read, I don't mind it too much.

like image 29
ParkourGrip Avatar answered Sep 30 '22 14:09

ParkourGrip