Skip to main content

injectAtomSelector

import { injectAtomSelector } from '@zedux/react'

An injector that accepts an AtomSelector and registers a dynamic graph dependency on the selector's cache.

The selector will rerun every time any of its own dynamic dependencies update. The atom instance that uses this injector will only reevaluate when the selector result changes.

Caches the selector's result in the ecosystem's .selectors if it hasn't been cached yet. If this selector has been cached before with the exact same arguments, the selector doesn't run, and injectAtomSelector() returns the cached result.

Example

Live Sandbox
123456789101112131415161718192021222324252627282930313233343536
const countersAtom = atom('counters', () => {
return injectStore({ counterA: 1, counterB: 1 })
})

const wrapperAtom = atom('wrapper', () => {
const counterA = injectAtomSelector(({ get }) => get(countersAtom).counterA)
const instance = injectAtomInstance(countersAtom)
const { setState } = instance

return api({
counterA,
counterB: instance.getState().counterB,
}).setExports({
incrementA: () =>
setState(state => ({ ...state, counterA: state.counterA + 1 })),
incrementB: () =>
setState(state => ({ ...state, counterB: state.counterB + 1 })),
})
})

function Counters() {
const { counterA, counterB } = useAtomValue(wrapperAtom)
const { incrementA, incrementB } = useAtomInstance(wrapperAtom).exports
const rendersRef = useRef(0)
rendersRef.current++

return (
<>
<div>Number of renders: {rendersRef.current}</div>
<div>Counter A (dynamic): {counterA}</div>
<button onClick={incrementA}>Increment Counter A</button>
<div>Counter B (static): {counterB}</div>
<button onClick={incrementB}>Increment Counter B</button>
</>
)
}

Miscellaneous:

// only reevaluate when `someField` changes:
const selectedVal = injectAtomSelector(({ get }) => get(myAtom).someField)

const withParams = injectAtomSelector(
({ get }) => get(myAtom, ['a param']).someField
)

const selectorComposition = injectAtomSelector(
({ select }) => `${select(helloSelector)}, ${select(worldSelector)}!`
)

const staticVal = injectAtomSelector(
({ getInstance }) => getInstance(myAtom).getState().someField
)

const staticValUsingEcosystem = injectAtomSelector(
({ ecosystem }) => ecosystem.get(myAtom).someField
)

const withSelectorConfig = injectAtomSelector({
name: 'example',
resultsComparator: (newVal, oldVal) => _.isEqual(newVal, oldVal),
selector: ({ get }) => get(myAtom, ['a param']).someField,
})

// passing a selector cache directly:
const cache = ecosystem.selectors.getCache(mySelector) // doesn't subscribe
const value = injectAtomSelector(cache) // subscribes

Signature

injectAtomSelector = (selectable, ...args) => result
selectable

Required. An AtomSelector, AtomSelectorConfig object, or a SelectorCache instance.

It's recommended to pass a stable function/object reference whenever possible for best performance.

If an AtomSelector or AtomSelectorConfig object is passed, injectAtomSelector() runs the selector and caches the value if it hasn't been cached yet. If the selector has been cached before with the exact params (deep equality), Zedux doesn't run the selector and returns the cached value.

If a SelectorCache is passed, injectAtomSelector() simply returns the cached value.

In all cases, injectAtomSelector() registers a dynamic dependency on the resolved selector cache - the current atom instance will reevaluate whenever the selector result changes

args

Required if the selector takes arguments. Must not be passed otherwise.

Selector arguments should always be serializable values (no functions). You can remove this requirement via the complexParams ecosystem config option (not recommended).

Returns

The result of running the selector. If the given selector + args combo has been cached before, injectAtomSelector() returns the cached value.

See Also