0

I have 3 useEffect functions each calling a updateData function. (Each one is doing something else in addition to that so I can't combine them all.) Because of this, on page load, updateData gets called 3 times.

Here's the relevant code:

useEffect(() => {
    ...
    updateData();
}, [changePage]);

useEffect(() => {
    ...
    updateData();
}, [search]);

useEffect(() => {
    ...
    updateData();
}, [sortBy]);

How can I make sure that updateData only gets called once on page load?

Jessica
  • 9,379
  • 14
  • 65
  • 136
  • Is it incorrect, that updateData gets executed when `sortBy` or `changePage` or `search` change? – Julian Kleine Mar 03 '20 at 11:53
  • Why is it insufficient to make one useEffect with three dependencies? Does updateData change any of the three deps values? – Julian Kleine Mar 03 '20 at 11:54
  • That will run once for each effect one time... next time it will run when the observed props has any change. – Jai Mar 03 '20 at 11:54
  • @Jai How can I make it run once initially, not for each effect on page load – Jessica Mar 03 '20 at 11:59
  • I think you have to "protect" your `updateData()` with some if statement. – Joe Lloyd Mar 03 '20 at 12:01
  • According to your method names, the `updateData` function is the same in all cases with different query parameters, i.e. `api/data?serach=''&sort='ac'&page=0` if that is true, then you do not need three hooks, one hook can manage all, the problem is with the state where you keep these data – Amir-Mousavi Mar 03 '20 at 12:11

2 Answers2

0

What i can suggest you to use another useEffect with useState. What i need to check is if a state prop is truthy only then all should run. To limit this i would use an if condition to check if that state value is true then run it otherwise don't.

What i am thinking is:

const [isLoaded, setIsLoaded] = useState(false);
useEffect(() => {
  if (isLoaded && changePage) {
    updateData(); // <---wont run as isLoaded is false at first load
    setIsLoaded(false);
  }
}, [changePage]);

useEffect(() => {
  if (isLoaded && search) {
    updateData();// <---wont run as isLoaded is false at first load
    setIsLoaded(false);
  }
}, [search]);

useEffect(() => {
  if (isLoaded && sortBy) {
    updateData();// <---wont run as isLoaded is false at first load
    setIsLoaded(false);
  }
}, [sortBy]);

useEffect(() => {
  setIsLoaded(true); // <---sets the isLoaded to true for further observations
  if(isLoaded){
     updateData(); // <----calls the updateData once.
  }
}, []);

Note:- Order is important.

Jai
  • 74,255
  • 12
  • 74
  • 103
  • ha, we ended up with very similar solution. Dono why someone is downvoting them. probably one of the others with bad answer. +1 – Joe Lloyd Mar 03 '20 at 12:43
  • I didn't try it, but from reading the code it doesn't look like `updateData` will get called when `sortyBy, search or changePage` changes – Jessica Mar 03 '20 at 15:55
-2

Add a mount state

I think this will work. But it feels messy to me. Also maybe state get batched together and you might get some extra triggers from that. So please test it with your setup.

const [isMountRender, setMountRender] = useState(true);

useEffect(() => {
    ...
    if (isMountRender) return;
    updateData();
}, [changePage]);

useEffect(() => {
    ...
    if (isMountRender) return;
    updateData();
}, [search]);

useEffect(() => {
    ...
    if (isMountRender) return;
    updateData();
}, [sortBy]);

useEffect(() => {
    setMountRender(false)
    updateData();
}, []);
Joe Lloyd
  • 19,471
  • 7
  • 53
  • 81