Skip to content

Instantly share code, notes, and snippets.

@artembykov
Last active April 29, 2024 09:55
Show Gist options
  • Save artembykov/b4fc874070df544684231a4dc500d762 to your computer and use it in GitHub Desktop.
Save artembykov/b4fc874070df544684231a4dc500d762 to your computer and use it in GitHub Desktop.
React hook for async operations
import { useCallback, useEffect, useState } from "react";
export default (asyncFunction, dependencies) => {
const memoizedAsyncFunction = useCallback(asyncFunction, dependencies);
const [resultGetter, setResultGetter] = useState(() => () => { });
useEffect(() => {
const controller = new AbortController();
const signal = controller.signal;
memoizedAsyncFunction(signal).then(
result => {
return () => result;
},
error => {
return () => { throw error };
},
).then(getter => {
if (!signal.aborted) {
setResultGetter(() => getter);
}
});
return () => controller.abort();
}, [memoizedAsyncFunction]);
return resultGetter;
};
@artembykov
Copy link
Author

artembykov commented Mar 28, 2020

Description

useAsync returns a getter function, which should be used to obtain the actual outcome of an async operation.

Getter function behavior mimics states of a Promise:

Function behavior Promise state
Return undefined pending
Return actual value fulfilled
Throw exception rejected

Example

The following React component fetches weather data for specific locations from public API:

import React from 'react';
import useAsync from './useAsync.js';

const Weather = props => {
  const getWeather = useAsync(signal => {
    const url = `https://wttr.in/${props.query}`;
    return fetch(url, { signal }).then(response => response.json());
  }, [props.locationId]);
  
  try {
    const weather = getWeather();
    
    switch (weather) {
      case undefined:
        return null;
      default:
        return <div>{JSON.stringify(weather)}</div>;
    }
  } catch (error) {
    return <div>{String(error)}</div>;
  }
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment