Programmatic Control
In some cases, you may want to control the state or context values of a machine
programmatically via its props
or based on certain conditions. This is
typically know as "controlling" the components.
Zag provides a number of ways to control the state of a machine programmatically.
Setting initial context
All machines have an "internal" context value that is used to manage extended
state (or data) within the machine. To extend the initial value of this context,
we allow users pass it directly into the machine
function.
This is used to set/override the initial context value of the machine. It can't be updated later on. Keep reading to see how to update it.
For example, if you want an accordion to start with a specific selected value. Here's how to acheive that:
const [state, send] = useMachine( // set initial context value accordion.machine({ value: "item-1", }), )
Using exposed methods
The connect
method of the machines provide helpful methods (APIs) to change
the machine state or update its context.
This approach is the recommended approach to programmatically update a machine.
Let's say we'd like to change the expanded accordion item in an accordion group. Here's how to do that:
function Accordion() { // 1. Bind the machine in your framework const [state, send] = useMachine(accordion.machine) // 2. Call the connect function const api = accordion.connect(state, send) // 3. Use exposed methods api.setValue("item-1") return (...) }
Now, let's say you'd like to udpate the selected accordion based on props passed
to the Accordion
component, here is how to do that in React:
import useUpdateEffect from "use-update-effect" function Accordion(props) { const [state, send] = useMachine( accordion.machine({ value: props.value, }), ) const api = accordion.connect(state, send) useUpdateEffect(() => { api.setValue(props.value) }, [props.value]) return (...) }
Transient updates
In some edge-cases, you may want to update the machine's context
programmatically without sending an event to the machine or using the provided
api
.
You can pass the context value to the useMachine
hook directly. We recommend
memoizing the context to ensure it's stable between re-renders.
// ❌ Don't do this const [state, send] = useMachine(accordion.machine, { context: { value: props.value, }, }) // ✅ Do this const [state, send] = useMachine(accordion.machine, { context: useMemo( () => ({ value: props.value, }), [props.value], ), })
This only works for context updates, not internal state updates and is not recommended.
Edit this page on GitHub