skip to Main Content

I am building a react component as a functional component.
I am gonna narrow it down here to a minimal problem, you can imagine it as a DataGrid containing data that is fetched from an external API which is saved to that state so that it can be used for the DataGrid.

[orders, setOrders]  = React.useState(getSomeIntialValuesToShowWhileFetching())

Then I have the useEffect hook to run only on mounting to fetch the data.

useEffect(() => {
let res = await getDataFromApi();
setOrders(res);

}, [])

So far so good. Now I have another calculation, that needs to be done after orders was filled with the data, think of it as a total of all orders.
How do I achieve this, due to the async nature of setOrders(res) ?

I tried using another useEffect, that has orders in its dependency array. The problem here is that this also runs on the inital mounting of the component.

As setOrders is asynchronously but does not return a Promise, I don´t see a way to await it or chain it with then operations.

I am grateful for answers as I am still learning how to deal with hooks.

2

Answers


  1. You can use another UseEffect that has orders in its dependency array, but with a conditional that checks if orders received any value. Example:

    useEffect(() => {
    if (orders.length < 1 ) {
      return;
    }
    // get total orders
    }, [orders]);
    
    Login or Signup to reply.
  2. You might consider using a custom hook known as useDidUpdateEffect. In essence, it is a normal useEffect but slightly modified to skip the initial render.

    It uses the didMountRef as a flag, which is false on init. Hence your function will run only if didMountRef.current == true which happens after the initial render.

    That way your calculation will only run when your dependency(orders) actually updates.


    Hook definition

    import { useEffect, useRef } from 'react';
    
    export function useDidUpdateEffect(fn, deps) {
      const didMountRef = useRef(false);
    
      useEffect(() => {
        if (didMountRef.current) { 
          return fn();
        }
        didMountRef.current = true;
      }, deps);
    }
    

    Usage

    import { useDidUpdateEffect } from '/your/hooks/path';
    
    useDidUpdateEffect( () => {
        calculation();
    }, [orders] )
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search