1
votes

I am not sure if this is a valid warning by using useEffect around the dependency array, it seems like whenever variable, method or dispatch inside the useEffect are giving warning that React Hook useEffect has missing dependencies: 'active', 'retrieveUser', and 'dispatch'. Either include them or remove the dependency array of following example, if I just leave it as blank array to perform the componentDidMount functionality

useEffect(() => {
   setActive(active);   
   await retrieveUser(param1, param2);
   dispatch(someAction);
}, []).        // warning: React Hook useEffect has missing dependencies: 'active', 'retrieveUser', 'param1', 'param2', and 'dispatch'. Either include them or remove the dependency array, but here I just want to perform componentDidMount concept so my dependency list has to be empty

or

useEffect(() => {
   await retrieveUser(param1, param2);
   dispatch(someAction);
}, [userId]).   // warning: React Hook useEffect has missing dependencies: 'retrieveUser', 'param1', 'param2', and 'dispatch'. Either include them or remove the dependency array

Are those valid warning? Especially that I just want to monitor on specific data field, what's the point of adding all inside dispatch or method into the dependency array if I can't add anything into the dependency list(for componentDidMOunt) or I just want to monitor userId, not param1, param2, etc

2
What is the concern with adding those functions that won’t change such as dispatch? - Alexander Staroselsky
dispatch is fine, but adding method into the dependency list makes me confusing, once I did that, my existed method has another warning to suggest using useCallback...also if my method includes some other parameters, e.g await retrieveUser(param1, param2, param3) it also suggest to add param1, param2, param3 into dependency list, but I just want to watch if userId changes, whether param1 changes are should not fire the useEffect - Kev D.

2 Answers

2
votes

React is giving this warning because you are using part of your component's state or props in useEffect but have told it not to run the useEffect callback when that state/props changes. React assumes you will want to run that useEffect() whenever the referenced states change so it is giving you a warning. If you were only referencing variables outside of state or props, you would not get this warning. See below for info about conditionally running useEffect.

Since your goal is to only run useEffect only sometimes, you're likely going to need to restructure your component so that different data is in or out of state. It's difficult to recommend more specific solutions without knowing more about the component; but, a good goal is to have the state you utilize in useEffect match up with the changes that you want to trigger a rerender.

There might be other issues with state in your component. For example, I notice that you call setActive(active);. If active is part of the component's state, that means you are setting active to itself. Which isn't necessary. (this is assuming you are following typical naming patterns and likely have a line at the top of your component like:

const [active, setActive] = useState(initialValue);


Conditionally running useEffect

When you provide a second argument to useEffect(), it limits the situations when useEffect runs the callback function on rerenders. This is for performance reasons as explained in the React docs.

In the first useEffect where you provide an empty array, you are telling React to only run those actions (setActive(active)...etc.) when the component mounts and unmounts.

In the second useEffect where you provide an array with userId, you are telling React to only run the callback on mount, unmount, and whenever userId changes.

React is giving you that warning because it knows it won't run useEffect if active...etc or other values change. This can cause different parts of your component to be referencing different states. For example, one part of your component might be using userId = 1 and another part is using userId = 2. This is not how React is designed to work.

0
votes

Create a hook that executes only once:

const useEffectOnce = effect => {
    useEffect(effect, []);
};

use this hook inside your component

useEffectOnce(() => {
    const request = async () => {
        const result = await retrieveSum(param1, param2);
        setResult(result);
    };

    request();
});

Now, even if your props (param1, param2) change, the effect is called only once. Be very careful when doing this, the component is probably buggy unless your initial props are truly special. I don't see how this is different from disabling the rule with

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

Demo: https://codesandbox.io/s/trusting-satoshi-fngrw?file=/src/App.js