injectEffect
import { injectEffect } from '@zedux/react'
An injector that attaches a side effect to an atom instance. Runs the effect on initial atom evaluation and again every time the passed dependencies change on subsequent evaluations.
This is almost exactly equivalent to React's useEffect()
hook. injectEffect()
has two additional features:
injectEffect()
accepts an async callback function (a function that returns a promise).injectEffect()
accepts a 3rdconfig
parameter.
Async Callback
injectEffect(async () => {
const val = await fetchVal()
}, [])
This is only for convenience in cases where you don't have any cleanup. When you do have cleanup tasks to perform, the basically ugly useEffect
workarounds are still what we use:
injectEffect(() => {
const controller = new AbortController()
const asyncFn = async () => {
const data = await fetch(url, { signal: controller.signal })
...
}
return () => controller.abort()
})
We may make useEffect
callbacks take an AbortController to hook into to perform cleanup tasks. If that sounds useful for you, open an issue and let's discuss!
SSR
injectEffect()
does not run the callback when the ssr
ecosystem config option is set to true. This mimics useEffect
's SSR behavior.
Examples
Miscellaneous:
// empty deps - only runs once - when the atom instance is created.
injectEffect(sideEffect, [])
// no deps - runs on every evaluation
injectEffect(sideEffect)
// with deps - runs again when any deps change
injectEffect(sideEffect, [depA, depB])
// return a cleanup function that will run when this atom instance is destroyed
injectEffect(() => {
const subscription = stream.subscribe(...)
return () => subscription.unsubscribe()
}, [])
// the cleanup function will also run every time deps change
injectEffect(() => {
const subscription = stream.subscribe(...)
return () => subscription.unsubscribe()
}, [depA, depB])
// async functions supported (can't return a cleanup function if you do this)
injectEffect(async () => {
const val = await fetchVal()
})
Signature
- Simplified
- TypeScript
injectEffect = (effect, deps?, config?) => void
declare const injectEffect: (
effect: EffectCallback,
deps?: InjectorDeps,
config?:
| {
synchronous?: boolean | undefined
}
| undefined
) => any
Required. A function.
The effect can do anything but it shouldn't reference unstable variables outside the effect, unless those variables are added to the deps
array.
Signature:
- Simplified
- TypeScript
effect = () => cleanup
effect: () => (() => void) | Promise<any> | void
A cleanup function, a promise, or nothing.
Return a function to clean up subscriptions, clear timeouts, destroy resources, and generally prevent memory leaks.
If a cleanup function is returned, it will be called when the effect reruns due to deps changing or when the current atom instance is destroyed. On deps change, this is called before the effect function is rerun.
Optional (though you'll almost always want to pass it). An array containing absolutely anything.
If any items in this array change on a subsequent evaluation, the previous effect's cleanup function will be called (if you returned one) and the effect will be rerun.
Pass an empty array to prevent the effect from ever rerunning, as long as this atom instance is alive:
injectEffect(oneOffEffect, [])
If not passed, the effect will rerun on every evaluation. This is almost never what you want.
Optional. An object containing a single optional boolean property:
{ synchronous }
By default, injectEffect()
defers executing the side effect until the next turn of the event loop. This mimics useEffect
's behavior.
Passing { synchronous: true }
prevents injectEffect()
from deferring execution of the callback. It will run immediately.
This can be useful for situations where you're expecting an atom to be used exclusively outside React. The default behavior of deferring side effects can be counterintuitive when e.g. an atom instance is created, used, and destroyed synchronously in one turn of the event loop. In this case, effects declared in that atom will never run. Use the synchronous
option to make sure they do.