State¶
Advanced topic!
This API doc covers reactive state (mo.state
), an advanced topic.
You likely don’t need reactive state. UI elements already have built-in
state, their associated value, which you can access with their value
attribute.
For example, mo.ui.slider()
has a value that is its current position on an
interval, while mo.ui.button()
has a value that can be configured to
count the number of times it has been clicked, or to toggle between True
and
False
. Additionally, interacting with UI elements bound to global variables
automatically executes cells that reference those
variables, letting you react to changes by just reading their
value
attributes. This functional paradigm is the preferred way of
reacting to UI interactions in marimo. So if you
think you need to use mo.state
, make sure to first read the guide on
interactivity. Chances are, the reactive execution
built into UI elements will suffice. (For example, you don’t need reactive
state to handle a button click.)
That said, here are some signs you might need mo.state
:
you need to maintain historical state related to a UI element that can’t be computed from its built-in
value
(e.g., all values the user has ever input into a form)you need to synchronize two different UI elements (e.g., so that interacting with either one controls the other)
you need to introduce cycles across cells
If one of these cases applies to you, then read on. mo.state
lets you
make all kinds of interesting applications, but like mutable state in general,
it can complicate notebook development and has the potential to
introduce hard-to-find bugs.
- marimo.state(value: T, allow_self_loops: bool = False) tuple[marimo._runtime.state.State[T], Callable[[T], NoneType]] ¶
Mutable reactive state
This function takes an initial value and returns:
a getter function that reads the state value
a setter function to set the state’s value
When you call the setter function and update the state value in one cell, all other cells that read any global variables assigned to the getter will automatically run. By default, the cell that called the setter function won’t be re-run, even if it references the getter; to allow a state setter to possibly run the caller cell, use the keyword argument
allow_self_loops=True
.You can use this function in conjunction with
UIElement
on_change
handlers to trigger side-effects when an element’s value is updated. For example, you can tie multiple UI elements to derive their values from shared state.Basic Usage.
Create state:
get_count, set_count = mo.state(0)
Read the value:
get_count()
Update the state:
set_count(1)
Update the state based on the current value:
set_count(lambda value: value + 1)
Note: Never mutate the state directly. You should only change its value through its setter.
Synchronizing multiple UI elements.
get_state, set_state = mo.state(0)
# updating the state through the slider will recreate the number (below) slider = mo.ui.slider(0, 100, value=get_state(), on_change=set_state)
# updating the state through the number will recreate the slider (above) number = mo.ui.number(0, 100, value=get_state(), on_change=set_state)
# slider and number are synchronized to have the same value (try it!) [slider, number]
Warning. Do not store
marimo.ui
elements in state; doing so can lead to hard-to-diagnose bugs.Args:
value
: initial value of the stateallow_self_loops
: if True, if a cell calls a state setter and also references its getter, the caller cell will be re-run; defaults toFalse
.
Returns:
getter function that retrieves the state value
setter function that takes a new value, or a function taking the current value as its argument and returning a new value