Skip to main content

AtomInstance

All standard atoms (aka "atom instances") are actually instances of this class. When Zedux instantiates atom templates (and ion templates), it's just creating instances of this class.

Creation

You should never instantiate this class yourself. Zedux does it for you. An instance is created the first time a given atom template + params combo is used.

Many hooks and injectors return instances of this class.

import { useAtomInstance } from '@zedux/react'
import { myAtom } from './atoms'

function MyComponent() {
// creates the instance if it doesn't exist yet
const instance = useAtomInstance(myAtom)
...
}

Providing

An atom instance can be provided over React context via <AtomProvider>.

import { AtomProvider, useAtomInstance } from '@zedux/react'
import { myAtom } from './atoms'

function Parent() {
const instance = useAtomInstance(myAtom)

return (
<AtomProvider instance={instance}>
<Child />
</AtomProvider>
)
}

Consume provided instances with useAtomContext()

import { useAtomContext } from '@zedux/react'
import { myAtom } from './atoms'

function Child() {
const instance = useAtomContext(myAtom)
}

Extending

There are many aspects of an atom instance's behavior you can change when extending this class. This is an extremely advanced feature. We're not documenting it yet as the internals of this class may change.

Properties

Atom instances have the following readonly properties:

ecosystem

A reference to the ecosystem that created and controls this atom instance.

exports

An object. May be undefined, if nothing was exported.

The exports of the atom instance, as defined by the instance's returned AtomApi.

This object is stable. It is set the first time an atom instance is created and will not change on subsequent evaluations.

import { api, atom } from '@zedux/react'

const exportsAtom = atom('exports', () => api().setExports({ hello: 'world' }))

const importAtom = atom('import', () => {
const { hello } = injectAtomInstance(exportsAtom).exports
})
id

A string. This is the stable, unique id of this atom instance in the ecosystem. This id is the combination of the atom template's key and a deterministic stringification of the params of this atom instance. Zedux uses this internally to identify this atom instance in the graph and atom instances cache.

ecosystem.getInstance(atom('a', null)).id // 'a'
ecosystem.getInstance(
atom('b', (param: string) => param),
['c']
).id // 'b-["c"]'
nextReasons

An array that tracks the batched EvaluationReasons that will lead to the atom instance reevaluating.

If the atom instance is currently evaluating, this is the list of reasons explaining why and is what ecosystem.why() will return.

This will be empty if no reevaluation is currently scheduled or if this is the first evaluation of the atom instance.

prevReasons

An array that tracks the batched EvaluationReasons describing why the atom instance last evaluated. This will be empty if the last evaluation was the first.

params

A reference to the raw, unserialized params that were used to create this atom instance. If the atom doesn't take params, this will be an empty array.

const instanceA = useAtomInstance(myAtom, ['param 1', 'param 2'])
const instanceB = useAtomInstance(myAtom, ['a', 'b'])
instanceA.params // ['param 1', 'param 2']
instanceB.params // ['a', 'b']

All params must be serializable (no functions or symbols)! This is because Zedux converts the params to a stable string representation in order to efficiently check for an existing atom instance with the "same" params.

Sameness is determined by deep value comparison, not reference equality. Order matters!

// These params are the "same" in Zedux's eyes:
useAtomInstance(myAtom, ['a', { b: 'b', c: 'c' }])
useAtomInstance(myAtom, ['a', { c: 'c', b: 'b' }])

// But these are different:
useAtomInstance(myAtom, ['a', 'b'])
useAtomInstance(myAtom, ['b', 'a'])

The only exception to the serializable rule is other atom instances. That's right! You can pass an atom instance to another atom instance. You can then use get(), injectAtomValue(), or any other dynamic injector to register a dynamic graph dependency on the passed atom instance.

Live Sandbox
1234567891011121314151617181920
const normalAtom = atom(
'normal',
'row, row, row your boat gently lest I scream'
)

const shoutingAtom = atom(
'shouting',
(instance: AtomInstance<AtomGenericsPartial<{ State: string }>>) => {
const val = injectAtomValue(instance) // subscribe to updates

return val.toUpperCase()
}
)

function Shout() {
const instance = useAtomInstance(normalAtom)
const shout = useAtomValue(shoutingAtom, [instance]) // just pass the instance

return <div>{shout}</div>
}
promise

A promise. May be undefined if no promise was set on a returned AtomApi.

This promise will be used to cause React to suspend whenever this atom instance is used in a component until the promise completes. This promise reference will change if a subsequent evaluation returns a new promise.

status

A string representing the status of the atom instance:

Initializing -> Active <-> Stale -> Destroyed

You typically shouldn't need to look at this but you may, for example, want to check that instance.status !== 'Destroyed' when holding a reference to an atom instance outside of React/atoms (and if it is, update your local reference using ecosystem.getInstance()).

store

A Zedux store. A reference to this atom instance's store. If the state factory returned a store, this is a reference to that store.

template

A reference to the atom template that this atom instance was created from.

Methods

addDependent

Manually adds a graph edge between this atom instance and a new external "pseudo" graph node. See the destruction walkthrough.

Signature:

addDependent = (config?) => cleanup
config

Optional. An object containing the following optional properties:

{ callback, operation }
callback

A DependentCallback function.

operation

A string. Can be anything. This can be useful when debugging your selector graph. It essentially labels the edge, showing what operation caused the graph edge to be added.

destroy

Destroys the atom instance. Does nothing if the instance is already destroyed. Destruction bails out by default if the atom instance currently has dependents.

Pass true to force destruction regardless of whether this atom instance has dependents. This will schedule a task to tell any dependents to automatically create a new instance after this one is destroyed.

instance.destroy() // only destroy if not used elsewhere
instance.destroy(true) // force destruction

See the Destruction walkthrough.

dispatch

An alias for .store.dispatch().

getState

An alias for .store.getState().

invalidate

Forces the atom instance to reevaluate.

Live Sandbox
1234567
const coinTossAtom = atom('coinToss', () => Math.random() < 0.5)

function Coin() {
const isHeads = useAtomValue(coinTossAtom)
const { invalidate } = useAtomInstance(coinTossAtom)

return <button onClick={invalidate}>{isHeads ? 'Heads' : 'Tails'}</button>

A reference to this function is returned from injectInvalidate().

setState

An alias for .store.setState().

setStateDeep

An alias for .store.setStateDeep().

See Also