3

I am trying to delete items from state variable in useEffect using the props comming to the component. I want to take initial values from state variable and then delete elements in that array and set the state variable again to new value. But When I don't pass the state variable in dependency array it is throwing warning as React Hook useEffect has a missing dependency: 'abc'. Either include it or remove the dependency array and when I pass it, It goes in infinite loop which I think is correct because of useeffect working. This is the useffect I am trying:

const [abc, setAbc] = useState([]);

useEffect(() => {
    axios.get(url).then(res => setAbc(res));
}, [props.bbb])

useEffect(() => {
    if(props.xyz) {
         let aaa = abc.filter(key => key.id === props.xyz);
         setAbc(aaa);
    }
}, [props.xyz])

Is there something I am missing here? Is there any better way to do this?

Thanks in advance.

user11823877
  • 143
  • 1
  • 15
  • 1
    you can use `setAbc(currentAbc => currentAbc.filter(key => key.id === props.xyz))` and not provide `abc` as a dependency. – Jacob Smit Jul 22 '21 at 05:44
  • Curios, why do you have two `useEffect` hooks that have the same dependency ***and*** update the same state? Which do you want to win out and update state? – Drew Reese Jul 22 '21 at 05:55
  • I assumed the two `useEffect`s should be one, I'm reading the intended logic as "On change of XYZ reload complete list and then filter based on XYZ" would need more information to be sure. – Jacob Smit Jul 22 '21 at 06:01
  • @JacobSmit I don't disagree, other than the first seems to be more the typical fetch data when mounting otherwise it doesn't make sense to run both each time the `xyz` prop updates. The promise chain of the first will overwrite any filtering the second did since it's asynchronous. – Drew Reese Jul 22 '21 at 06:03
  • Hey. Actually I added the same variables here bymistake. Updated the code. Both use effect have different dependencies. – user11823877 Jul 22 '21 at 11:41
  • Thanks you @JacobSmit. setAbc(currentAbc => currentAbc.filter(key => key.id === props.xyz)) this worked – user11823877 Jul 22 '21 at 11:49

1 Answers1

1

Correct, including a dependency that the effect updates will likely cause render looping. Use a functional state update to eliminate the need for abc as a dependency.

useEffect(() => {
  if (props.xyz) {
    setAbc(abc => abc.filter(key => key.id === props.xyz));
  }
}, [props.xyz]);

Since the first useEffect doesn't actually reference props I'm going to maybe assume you meant to only call this on mount. You can do this by using an empty dependency array.

useEffect(() => {
  axios.get(url).then(res => setAbc(res));
}, []);

Update

If you are wanting to fetch abc and filter each time the props.xyz dependency updates then use a single useEffect hook and filter the result before updating state.

useEffect(() => {
  axios.get(url)
    .then(res => {
      if (props.xyz) {
        setAbc(res.filter(key => key.id === props.xyz));
      } else {
        setAbc(res);
      }
    });
}, [props.xyz]);
Drew Reese
  • 165,259
  • 14
  • 153
  • 181