DEV Community

Discussion on: Avoiding Race Conditions when Fetching Data with React Hooks

Collapse
 
n1ru4l profile image
Laurin Quast • Edited

This was popping up on my feed and I wanted to share my higher-level abstraction I built using a generator function API.

If you have many useEffect hook usages or complex useEffect logic, all the checking on whether the task should be canceled can become quite tedious.

Sample Usage:

const MyComponent = ({ filter }) => {
  const [data, setData] = React.useState(null);

  useAsyncEffect(
    function*() {
      const data = yield fetch("/data?filter=" + filter, {
        signal: controller.signal
      }).then(res => res.json());

      setData(data);
    },
    [filter]
  );

  return <Renderer data={data} />;
};

In case the effect is canceled (due to unmount or dependency array change), the Promise that was yield-ed will be ignored and the generator won't be invoked with the resolved value.

The API also allows registering optional cancelation handlers, which is quite handy for canceling in-flight requests.

const MyComponent = ({ filter }) => {
  const [data, setData] = React.useState(null);

  useAsyncEffect(
    function*(onCancel) {
      const controller = new AbortController();
      onCancel(() => controller.abort());

      const data = yield fetch("/data?filter=" + filter, {
        signal: controller.signal
      }).then(res => res.json());

      setData(data);
    },
    [filter]
  );

  return <Renderer data={data} />;
};

The library can be found here: github.com/n1ru4l/use-async-effect and I also wrote a blog article about it: dev.to/n1ru4l/homebrew-react-hooks...

I am currently also designing an API for the V2 which will also support Node.js style callbacks beside promises.

I hope it can help some of you ☺️