1

Fairly new to React here. In a situation like this, I have 2 values referenced in the callback. I only want the callback to be executed when the first value changes. Because I reference the second value, it still needs to be in the dep array; however, I don't want the callback to be execute every time the second value changes because it would be pointless in my code.

useEffect(()=> {
  // Do something with val1 and val2
}, [val1, val2]);

What is the best way to handle this situation?

I know useReducer exists, but I haven't learned it and I'm not sure if that is the solution to my problem.

UPDATE

I also know I can just add some logic inside the callback to return early if my val1 hasn't changed, but I was just wondering what the best approach is.

Joey Carlisle
  • 586
  • 4
  • 12
  • Consider using two `useEffect`s, removing `val1` from the first and `val2` from the second? – evolutionxbox Jun 24 '20 at 18:02
  • I need to use both values in a single API call – Joey Carlisle Jun 24 '20 at 18:05
  • I had the similar situation and it appeared that the problem was in the design of my state ---- Is there any problem with having the 2 variables in the dependencies? Could you add the code of the full component? – Arnaud Claudel Jun 24 '20 at 18:11
  • 1
    Could you elaborate on what `val` and `val2` are? Also, could you elaborate on the `something` you would like to do in the effect? – richytong Jun 24 '20 at 18:24

2 Answers2

1

Because you mentioned val1 and val2 are state variables, I recommend useReducer. As a rules of thumb, if you ever need to manipulate more than one state variable in an atomic operation, reach for this over useState. From the React documentation on useReducer

useReducer is usually preferable to useState when you have complex state logic that involves multiple sub-values

You can use useReducer to manage your component like this

  const [state, dispatch] = useReducer((state, action) => {
    if (action.type === 'changeVal1') {
      return { ...state, val1: action.val1 }
    }
    return state
  }, { val1: 'something', val2: 'anotherthing' })

  useEffect(()=> {
    const { val1, val2 } = state
    // do something with val1 and val2
  }, [state.val1]);

  // somewhere else in the component...
  dispatch({ type: 'changeVal1', val1 })
richytong
  • 2,387
  • 1
  • 10
  • 21
  • 1
    `As a rules of thumb, if you ever need to manipulate more than one state variable in an atomic operation, reach for this over useState` -> or it's an indicator that 2 state variables should be merged into a single object. I think that it's more an opinion rather than a general rule ---- `complex state logic that involves multiple sub-values` -> his situation looks fairly simple and a reducer looks overkill as there is just one possible action – Arnaud Claudel Jun 24 '20 at 19:13
0

Passing an array to useEffect as useEffect(callback, array) does not mean you are making the elements of the array available in the callback's scope. Those variables are already available to the callback declared in useEffect. The elements of the array are only meant to control whether or not the callback will fire on re-renders. In that regard, you will achieve your desired behavior like this

useEffect(()=> {
  // val 1 and val 2 are already in scope
  // Do something with val1 and val2
}, [val1]);

The above effect only executes the callback when val1 changes

richytong
  • 2,387
  • 1
  • 10
  • 21
  • If you're using `val2` inside the `useEffect` this will cause bugs. – evolutionxbox Jun 24 '20 at 18:10
  • @evolutionxbox how so? – richytong Jun 24 '20 at 18:12
  • It's not a problem of scope but rather of well designed functional component and state. Your code will generate a warning from React because you're using variables that are not in the depencies array. – Arnaud Claudel Jun 24 '20 at 18:12
  • Correct, but I use val2 inside my callback, so React warns me to put it into my dep array because if I don't, I will be referencing a stale val2 once val1 changes. At least thats how I understand it. – Joey Carlisle Jun 24 '20 at 18:18
  • React will warn you because it's a dangerous operation, but it's not an Error. You just have to be extra careful that your code is doing what you expect. – richytong Jun 24 '20 at 18:20
  • 1
    @richytong https://overreacted.io/a-complete-guide-to-useeffect/ and https://reactjs.org/docs/hooks-faq.html#why-am-i-seeing-stale-props-or-state-inside-my-function – evolutionxbox Jun 24 '20 at 18:21
  • I think to really move on from here, we'll need more context. – richytong Jun 24 '20 at 18:23
  • @richytong val1 and val2 are both `useState` values and then I make an API call with those values – Joey Carlisle Jun 24 '20 at 18:27
  • I see. In that case, you'll want `useReducer`. I'll put another answer – richytong Jun 24 '20 at 18:34