React Async offers three primary APIs: the useAsync hook, the <Async> component and the createInstance factory function. Each has its unique benefits and downsides.
As a hook
The useAsync hook (available from React v16.8.0) offers direct access to React Async's core functionality from within your own function components:
import { useAsync } from"react-async"// You can use async/await or any function that returns a PromiseconstloadPlayer=async ({ playerId }, { signal }) => {constres=awaitfetch(`/api/players/${playerId}`, { signal })if (!res.ok) thrownewError(res.statusText)returnres.json()}constMyComponent= () => {const { data,error,isPending } =useAsync({ promiseFn: loadPlayer, playerId:1 })if (isPending) return"Loading..."if (error) return`Something went wrong: ${error.message}`if (data)return ( <div> <strong>Player data:</strong> <pre>{JSON.stringify(data,null,2)}</pre> </div> )returnnull}
Using helper components can greatly improve readability of your render functions by not having to write all those conditional returns.
Because fetch is so commonly used with useAsync, there's a dedicated useFetch hook for it:
import { useFetch } from"react-async"constMyComponent= () => {constheaders= { Accept:"application/json" }const { data,error,isPending,run } =useFetch("/api/example", { headers }, options)// This will setup a promiseFn with a fetch request and JSON deserialization.// you can later call `run` with an optional callback argument to// last-minute modify the `init` parameter that is passed to `fetch`functionclickHandler() {run(init => ({...init, headers: {...init.headers, authentication:"...", }, })) }// alternatively, you can also just use an object that will be spread over `init`.// please note that this is not deep-merged, so you might override properties present in the// original `init` parameterfunctionclickHandler2() {run({ body:JSON.stringify(formValues) }) }}
useFetch takes the same arguments as fetch itself, as well as options to the underlying useAsync hook. The options object takes two special boolean properties: defer and json. These can be used to switch between deferFn and promiseFn, and enable JSON parsing. By default useFetch automatically uses promiseFn or deferFn based on the request method (deferFn for POST / PUT / PATCH / DELETE) and handles JSON parsing if the Accept header is set to "application/json".
As a component
The classic interface to React Async. Simply use <Async> directly in your JSX component tree, leveraging the render props pattern:
import Async from"react-async"// Your promiseFn receives all props from Async and an AbortController instanceconstloadPlayer=async ({ playerId }, { signal }) => {constres=awaitfetch(`/api/players/${playerId}`, { signal })if (!res.ok) thrownewError(res.statusText)returnres.json()}constMyComponent= () => ( <AsyncpromiseFn={loadPlayer} playerId={1}> {({ data, error, isPending }) => {if (isPending) return"Loading..."if (error) return`Something went wrong: ${error.message}`if (data)return ( <div> <strong>Player data:</strong> <pre>{JSON.stringify(data,null,2)}</pre> </div> )returnnull }} </Async>)
Using helper components can greatly improve readability of your render functions by not having to write all those conditional returns.
As a factory
You can also create your own component instances, allowing you to preconfigure them with options such as default onResolve and onReject callbacks.
import { createInstance } from"react-async"constloadPlayer=async ({ playerId }, { signal }) => {constres=awaitfetch(`/api/players/${playerId}`, { signal })if (!res.ok) thrownewError(res.statusText)returnres.json()}// createInstance takes a defaultOptions object and a displayName (both optional)constAsyncPlayer=createInstance({ promiseFn: loadPlayer },"AsyncPlayer")constMyComponent= () => ( <AsyncPlayerplayerId={1}> <AsyncPlayer.Fulfilled>{player =>`Hello ${player.name}`}</AsyncPlayer.Fulfilled> </AsyncPlayer>)
With helper components
Several helper components are available to improve legibility. They can be used with useAsync by passing in the state, or with <Async> by using Context. Each of these components simply enables or disables rendering of its children based on the current state.
Each of the helper components are also available as static properties of <Async>. In this case you won't have to pass the state object, instead it will be automatically provided through Context.