Skip to main content

injectPromise

import { injectPromise } from '@zedux/react'

An injector that creates a memoized promise reference. Returns an AtomApi with a promise and store attached. This AtomApi's store tracks the promise's state.

Accepts a promise factory function, a list of dependencies (similar to injectMemo() and injectEffect()), and an optional config object.

const atomApi = injectPromise(createPromise, [dep1, dep2], {
dataOnly,
initialState,
})
const { promise, store } = atomApi
note

injectPromise calls the factory function immediately to produce the promise. It doesn't defer the side effect like injectEffect would.

The state of the store returned by this injector is patterned after React Query's query state.

Example

Live Sandbox
1234567891011121314151617181920212223242526272829
const suspendingAtom = atom('suspending', () => {
const promiseApi = injectPromise(() => {
return new Promise(resolve => {
setTimeout(() => {
resolve('Hello, World!')
}, 2000)
})
}, [])

return promiseApi
})

function Child() {
const { data } = useAtomValue(suspendingAtom)

return (
<div>
The value: {data} (click "Reset" above if you missed the suspense)
</div>
)
}

function App() {
return (
<Suspense fallback={<div>Suspending...</div>}>
<Child />
</Suspense>
)
}

The advantage of using injectPromise over query atoms is that it gives you more control over when the promise is recreated.

It also gives you access to the promise and store so you can compose them with other promises/stores or handle/subscribe to them yourself.

Signature

injectPromise = (promiseFactory, deps?, config?) => atomApi
promiseFactory

Required. A function that returns a promise. Signature:

promiseFactory = (controller) => promise
controller

An AbortController. Use this controller's signal to abort fetch requests or run your own cleanup.

Will be undefined if AbortController is not available in the current environment.

Returns
The promise you want to memoize and whose state you want injectPromise's store to track.
deps

Optional. An array containing anything.

When any items in the array change on a subsequent evaluation, injectPromise() will call the promise factory again and reset the state of the store for the new promise.

Pass an empty array if you want the promise to never be recreated. Pass undefined to recreate the promise on every evaluation (not usually what you want).

config

Optional. An object with the following optional properties:

{ dataOnly, initialState, runOnInvalidate, ...storeConfig }
dataOnly

Optional. Boolean. Default false.

If true, the store's state will only contain the promise's resolved value (aka "data"), instead of an object containing data, isLoading, etc properties.

const { store } = injectPromise(promiseFactory, [])
store.getState() // { ...status flags..., data: <the data> }

// with dataOnly:
const { store } = injectPromise(promiseFactory, [], { dataOnly: true })
store.getState() // <the data>
initialState

Optional. Should match the type of the promise's resolved value. Default undefined.

The initial value of the store's data property. If dataOnly is true, this will be the entire state of the store.

Without this specified, the store's data will be undefined until the promise resolves

runOnInvalidate

Optional. Boolean. Default false.

If true, the promise factory will rerun when the current atom instance reevaluates due to an invalidate call.

Essentially a shorthand for doing this yourself:

const reasons = injectWhy()
const counterRef = injectRef(0)

if (reasons.some(reason => reason.type === 'cache invalidated')) {
counterRef.current++
}

const promiseApi = injectPromise(myPromiseFactory, [counterRef.current])
storeConfig

Optional. Configuration properties for the created store.

These are passed directly on to injectStore(). See available options here.

Returns

An AtomApi. This AtomApi's .promise property is a reference to the promise returned from the promiseFactory. This AtomApi's .store property is a store with a PromiseState shape that tracks the state of the promise.

This AtomApi can be returned directly from the atom state factory. Or you can consume/compose the promise and store however you want.

const { promise, store } = injectPromise(...)

See Also