The State is for component instances to store changing data. This could include anything from text a user entered into a form, data received from an API, or data that represents UI flow changes, such as the visibility of a modal. For more discussion of State, see Ramping Up with Modulo - Part 2.
By default (that is, with no
-store attribute), state data is unique to every
component instance, and components can never directly access sibling or parent
data. It is possible to indirectly reference it, however, by passing state data
from a "parent" component to a "child" components within the parent by passing
it via a Props attribute. In this case, the data should be considered
read-only to the child component, like any other Props data.
See below for a quick example, showing off an example of each of the 6 types of data:
State is traditionally included in Component definitions below the Template tag, but above the Script tag. This makes sense because functions in the Script tag typically manipulate state in order to render new HTML in the Template, making Script a sort of mutable bridge between Script and Template. State is defined in a similar way to Props: Only defined with properties, but no contents.
See below for an example of defining a State CPart:
Two State variables specified, of type String and Number:
Building up complicated JSON data with "." syntax:
Note that all "state variables" must have an initial value. It's okay to make
the initial value be
null (as in the "billable" example above), or other some
placeholder that will later be replaced. Undefined state variables are treated
If you want to share data between components globally, such that any component
can modify the data causing a re-render to all linked components, such as user
log-in information or global state data, then you can use the powerful
With this, any state with the given store throughout your application will share state and subscriptions to updates.
Limiting a store with -only
Sometimes, you'll only want to subscribe to certain attributes parts of a store:
The actual data in a State CPart is stored on it's "data" property. This
type. As an example, in a Script CPart, you can directly reference this
property with the code
When writing the State CPart definition, you must declare or pre-define each
"state variable" or property of the "data" Object that you want to use. It is
not permitted to create new state variables later on. In other words, if you
cparts.state.data as having
.title as "state
variables" (aka properties of the "data" Object), then an attempt like
cparts.state.data.newstuff = 10; may result in an error. If you are dealing
with a situation where you have an unknown quantity of data, such as from an
API, the correct approach is to store it all within a nested Object inside
the state data Object, e.g. such as an
data.apiResults Object or Array.
Unlike top-level "state variables", it's okay to add properties, modify, or
build upon nested Objects.
While it's allowed to assign any arbitrary reference as a State variable,
including complex, unserializable types such as function callbacks, it's highly
recommended to try to keep it to primitive and serializable types as much as
possible (e.g. String, Number, Boolean, Array, Object). The reason being that
there may be future features or third-party add-ons for State which will only
support primitive types (as an example, that would be required to save state to
localStorage). If you want to store functions, consider using a
prepareCallback to generate the functions within a Script context, and only
store the data needed to "generate" the function in the state (as opposed to
storing a direct reference to the function itself).
State contributes it's current data values to the renderObj. Examples:
- State initialized like:
<State name="Luiz">will be accessible on the renderObj like
renderObj.state.name, and in the Script or Template CParts like
- State initialized like:
<State stuff:='["a", "b"]'>will be accessible on the renderObj like
renderObj.state.info(with individual items accessed with code that ends with "
.stuff"), and in the Script or Template CParts like
State provides a single directive:
[state.bind]- Two-way binding with State data, with the key determined by the
name=property of whatever it is attached to. You can attach a
[state.bind]directive to any HTML
<input>, and the State CPart's two-way binding will cause the input value to be updated if the state variable ever changes, and if a user edits the input triggering a
"change"event, the state variable will be updated (along with, typically, a re-render of the component).
Examine below for how two different syntaxes can be used to construct data: Either the JSON style all in one go, or the somewhat more verbose (but perhapse easier to maintain) dataProp style:
- Useful resource: Read this for a full list of input types. With the exception of some of the ones listed below, they will all be "String" in terms of the State CPart. MDN input Element documentation
Example #1: Binding different input types
Example #2: Combining with filters
Example #3: Specifying events
Example #1: Store for simple state sharing
Example #2: Multiple States and bound buttons
Here we have an incomplete "chat" component with two State CParts. This one shares state between instances of it. Note that "msg" is not shared (neither is Props), but "messages" is shared.