2

I am using useEffect in react to listen to redux(easy-peasy) state change, but I want to listen to 1st value change only.
Because when my page loads the state has a default value and then API call is made and hence data changes but the API is a polling API, hence it keeps getting the data again and again in a short interval of time. But one of my requirement is to listen only to the 1st API data.

This is what I tried:

1st Approach with empty dependency

useEffect(() => {
        // my code 
    },[])

In this case, I get the default value of my state and not the 1st API response.

2nd Approach with state property in the dependency

useEffect(() => {
        // my code
    },[myState])

In this case, I keep getting the updated response from the API

both of these approaches didn't work for me. So please suggest a better solution.

Varun Sukheja
  • 6,170
  • 5
  • 51
  • 93
  • 2
    Why do you keep polling the API if you are not interested in the response? – hellogoodnight Mar 22 '21 at 08:28
  • Anyway, you could add a state variable that keeps track of if you should run the code inside the useEffect or not – hellogoodnight Mar 22 '21 at 08:29
  • The API call shouldn't be firing if you don't need the response. And an effect shouldn't be running if it doesn't need to. So you could probably optimise how you've set up your state and effects to prevent this. But for now a dirty fix would be to just use a ref and store whether or not it's been updating once. Then if so, at the top of your effect, you just check that ref and if it's already run, simple `return` – Jayce444 Mar 22 '21 at 08:29

2 Answers2

4

You can do so using a ref variable and comparing the state with initial state (which could be null, undefined, empty object depending on your implementation):

const hasRun = useRef(false)

useEffect(() => {
  if (!hasRun.current && myState !== initialState) {
    hasRun.current = true
    // run my code
  }
},[myState])

A ref variable won't participate in re-rendering.

Ajeet Shah
  • 18,551
  • 8
  • 57
  • 87
2

What I usually do with this is to have a "previous" state.

You can use this hook for to do that one:

const usePrevious(value) {
  const ref = useRef();

  useEffect(() => {
    ref.current = value;
  }, [value]); // only re-run if value changes

  // return previous value (happens before update in useEffect)
  return ref.current;
}

You can then do:


// I usually create a distinct initial state
const [var, setVar] = useState(null);
const prevVar = usePrevious(var);

useEffect(() => {
  if (var !== prevVar && var !== null) {
    // logic here
  }
}, [prevVar, var]);

Yers you can simplify this by not using the usePrevious hook, but the hook is quite handy and can be used to check the previous value and the current one.

I am L
  • 4,288
  • 6
  • 32
  • 49