You should initialize the data each time the useEffect is called inside useGet:

function useGet<TData>(getData: () => Promise<TData>): TData | undefined {

  const [data, setData] = React.useState<TData | undefined>(undefined);

  React.useEffect(() => {

    setData(undefinded) // initializing data to undefined

      .then((fetched) => setData(fetched));
  }, [getData]);

  // (TODO later -- handle abort of data fetching)

  return data;


In a reply on Twitter, @dan_abramov wrote that my useGet2 solution is more-or-less canonical:

If you do setState inside of render [and outside of useEffect] to get rid of stale state, it shouldn't ever produce a user-observable intermediate render. It will schedule another re-render synchronously. So your solution should be sufficient.

It's the idiomatic solution for derived state, and in your example state is derived from ID.

How do I implement getDerivedStateFromProps?

(In longer term there will be a different solution for data fetching altogether that doesn’t involve effects or setting state. But I'm describing what we have today.)

The article referenced from that link -- You Probably Don't Need Derived State -- explains what the root cause of the problem is.

It says that the problem is, expecting the "controlled" state passed-in to User (i.e. the userId) to match the "uncontrolled" internal state (i.e. the data returned by the effect).

The better thing to do is to depend on one or the other but not mix them.

So I suppose I should return a userId inside and/or with the data.

Related Query

More Query from same tag