ZeduxPlugin
The base class of Zedux ecosystem plugins.
A plugin can turn on ecosystem mods and hook into mod events. Mod events are just action objects containing info about stuff happening inside the ecosystem.
Plugins set up a sort of bidirectional stream with ecosystems:
- Plugins expose a
modStore
for ecosystems to subscribe to. This allows plugins to dynamically turn the mods they need on and off. - Ecosystems expose a
modBus
for plugins to subscribe to.
This class also has a single static property - actions
. This is an object mapping every available mod to an action factory that Zedux uses to dispatch mod events to plugins.
Mods have some overhead. That's why they're disabled by default. Turning them all on is probably not recommended in production builds of bigger apps. Dev tools might want them all on and that's probably fine in development.
Example
const plugin = new ZeduxPlugin({
initialMods: ['stateChanged'],
registerEcosystem: ecosystem => {
const subscription = ecosystem.modBus.subscribe({
effects: ({ action }) => {
if (action.type === ZeduxPlugin.actions.stateChanged.type) {
// handle stateChanged mod event
}
},
})
return () => subscription.unsubscribe()
},
})
const ecosystem = createEcosystem({ id: 'root' })
ecosystem.registerPlugin(plugin)
This should seem a little busy compared to most of Zedux's APIs. There is lots of room for abstracting some functionality, but for now we're keeping plugins intentionally low-level.
Creating
Plugins are a little lower-level. This is the only class in Zedux that you insantiate using the new
keyword.
const myPlugin = new ZeduxPlugin()
The constructor takes an optional config object:
{ initialMods, registerEcosystem }
Optional. An array of mod strings.
These don't need to be set initially. You can modify this list at any time by changing the state of your plugin's modStore
:
const plugin = new ZeduxPlugin()
plugin.modStore.setState({ stateChanged: true })
// This is equivalent to:
const plugin = new ZeduxPlugin({ initialMods: ['stateChanged'] })
Optional. A function that receives the ecosystem and can do anything with it.
Signature:
registerEcosystem = (ecosystem) => optionalCleanup
You can return a cleanup function to clean up subscriptions when the plugin is unregistered.
This is where you do all the plugin magic. Almost all plugins will pass this.
If your plugin turns on any mods, you'll likely want to subscribe to the ecosystem's modBus
to handle those mod events.
Properties
Every ZeduxPlugin has just two properties:
A Zedux store.
This store's state is an array of mod names. If a mod is in this list, it will be turned on in ecosystems where this plugin is registered. By default, this array is empty, unless you pass a list of initialMods.
You can change this store's state at any time to turn mods on/off in the ecosystem. When no plugins depend on a given mod, Zedux turns it off.
registerEcosystem
function passed to the ZeduxPlugin constructor or a no-op function if none was passed.Mod Details
Turn this mod on to receive a mod event when the ecosystem is wiped (usually as part of a reset).
Payload shape:
{
ecosystem: Ecosystem
}
Turn this mod on to receive a mod event every time an edge is created in the ecosystem's graph. This edge represents a dependency between two nodes in the graph.
This mod can also be used to determine when an edge has "moved" after a dependency was force-destroyed. Since no edgeRemoved
events are sent for edges between a force-destroyed node and its dependents, a plugin's internal graph representation would still have those edges intact when the new edgeCreated
events come in after the dependency is recreated. These edgeCreated
events will thus appear to be duplicates. When this happens, you can infer that the edge was "moved".
Payload shape:
{
dependency: AnyAtomInstance | SelectorCache
dependent: AnyAtomInstance | SelectorCache | string
edge: DependentEdge
}
dependent
will be a string if it's a "pseudo-node" in the graph, representing an external dependent like a React component.
You'll usually pair this mod with edgeRemoved
.
Turn this mod on to receive a mod event every time an edge is removed from the ecosystem's graph. This edge represents a dependency between two nodes in the graph.
Payload shape:
{
dependency: AnyAtomInstance | SelectorCache
dependent: AnyAtomInstance | SelectorCache | string
edge: DependentEdge
}
dependent
will be a string if it's a "pseudo-node" in the graph, representing an external dependent like a React component.
You'll usually pair this mod with edgeCreated
.
Turn this mod on to receive a mod event every time an atom instance or selector in the ecosystem finishes evaluating. This mod makes Zedux track evaluation time of every atom instance and selector.
Payload shape:
{
node: AnyAtomInstance | SelectorCache
time: number
}
node
is either an instance of AtomInstance
or SelectorCache
.
time
will be a DOMHighResTimestamp measured in milliseconds.
Note that this uses performance.now()
when available in the global scope. In other envs, it will fall back to using a non-high-res timestamp via Date.now()
.
Turn this mod on to receive a mod event every time an existing atom instance is reused anywhere.
This mod might be useful to find problematic duplicate atom keys. Though HMR/React Fast Refresh complicates this. Plugins can ignore overrides created via template.override()
by checking template._isOverride
.
Payload shape:
{
instance: AnyAtomInstance
template: AnyAtomTemplate
}
instance
references the existing atom instance being reused. template
is the atom template used to find the instance on this particular call.
Turn this mod on to receive a mod event every time an atom instance's state or an atom selector's cached result changes.
Payload shape:
{
action?: ActionChain
cache?: SelectorCache
instance?: AnyAtomInstance
newState: any
oldState: any
reasons: EvaluationReason[]
}
Either cache
or instance
will always be set.
If the atom or selector reevaluated due to this state change, reasons
will be set to the list of EvaluationReasons explaining the evaluation. Otherwise it will be empty.
Turn this mod on to receive mod events every time an atom instance's status
property transitions to a new state (e.g. from Initializing to Active or from Active to Stale).
This mod also triggers messages when selector caches are finished initializing and when selector caches are destroyed. Selectors don't track their lifecycle like atom instances do, but the newStatus
and oldStatus
fields for these events will be LifeCycle strings exactly like the strings used for atom instances.
Payload shape:
{
node: AnyAtomInstance | SelectorCache
newStatus: LifecycleStatus
oldStatus: LifecycleStatus
}
node
will be either an atom instance or an atom selector. You can use is()
to determine which.
oldStatus
will be one of "Active", "Initializing", or "Stale"
newStatus
will be one of "Initializing", "Stale", or "Destroyed"
Note that atom selectors can never be "Stale". Their lifecycle essentially goes Initializing -> Active -> Destroyed
.