- 13 Jun 2022
- 7 Minutes to read
- Updated on 13 Jun 2022
- 7 Minutes to read
Every Composer app that is running has what is called app state. It consists of two interlinked concepts: variables state and component state.
State in Composer vs. React
State in Composer apps is similar to React state (after all, the runtime is based on React/React Native), but there are some differences.
The main one is that you don't have to worry about creating any state management code – it just magically works.
Variables state describes the current in-memory data in your app: the current user, data loaded from a backend, a photo that was taken; but also things like latest GPS position or the width of the screen.
Variables can contain different types of (JSON-serializable) data: text strings, numbers, boolean values, arrays and objects
Types in Composer
Composer is strongly typed in that variable schema defines what values a variable is expected to hold, e.g.
currentQuantity can be defined to be a number, and
newUser to have certain object structure.
However, the typing is not strongly enforced: while we do our best to warn and in many cases even block you if something might result in a variable holding invalid data, nothing fundamentally explodes if you use Set page variable to store a text string in a number-type variable.
That said, if it seems like you can't use a variable in the way you intended it to or it works wrong, it's good to double-check that the variable's type has been set correctly.
Dynamic variables are the backbone of your app logic.
For the most part, the data they contain at any given time is determined by what flow functions have been called during the app runtime so far.
They are also affected by user interaction with view components that have input properties bound to dynamic variables, such as an input field or a dropdown.
Finally, you can set default values for dynamic variables via the Variables editor, but they are just the initial value and can be overwritten by app logic.
Page variables exist in the context of a single page. When a page is removed from the navigation stack, its page variables are reset.
Page variables are available under the
pageVars namespace in formulas.
Data variables are like page variables, but their schema is defined by the data resource they are linked to.
They also come with default logic that loads the associated data from the backend and stores it in the data variable.
When a page is removed from the navigation stack, its data variables are reset.
Data variables are available under the
data namespace in formulas.
App variables exist in the global context of the app. When the app opens for the first time, or is closed and reopened, app variables are reset.
App variables are available under the
appVars namespace in formulas.
Page parameters can only be of the text type.
Page parameters are read-only variables that can be set with the Open page flow function for the new page, e.g. ID of a product for a product details page. When the page is closed, page parameters are reset.
In the web runtime, page parameters are included in the URL as query parameters, so refreshing will re-init the page with the correct parameters.
Page parameters are available under the
params namespace in formulas.
Theme variables define how the various view components look, giving you an easy way to change the whole look-and-feel of your app.
They are available under the
theme namespace in formulas.
You can read more in the theme editor guide.
System variables define properties of the current app and the device its running on. They cannot be affected by the user directly, but change when the underlying property changes.
For example, resizing your browser window will affect
systemVars.os will be different on Android vs. iOS.
System variables are available under the
systemVars namespace in formulas.
You can read more in the system variables reference.
Sensor variables store data collected by device sensors, such as GPS position or accelerometer values.
Sensor variables are available under the
sensorVars namespace in formulas.
You can read more in the device sensors guide.
Component state defines how the view components in your app behave and render themselves.
View component state is essentially determined by the values of its various properties. There are several property types that all work together to describe the current state of the component:
- Display, input and configuration properties, available under the Properties tab in the properties panel
- Style properties, available under the Styles tab in the properties panel
You can read more about the different property types in the view component properties guide.
Most page properties are part of component state – under the hood, certain page properties such as background color or padding map to a root-level container component that's just not individually selectable on the view canvas.
Next, we'll cover the different ways to initialize component state and affect it during app runtime.
Static property values
Many component properties are set as static values in Composer, such as 0 padding for a Container or a Paragraph component's text content.
There can be different kinds of static property values, such as a string text for a button label or an array of label-value objects for a dropdown's option list.
A static property won't change on its own during app runtime, but can be changed via the Set component property and Set component styles flow functions.
However, in most cases you want to rather bind the property to a variable or formula and affect it that way, as this gives you a better grasp of what the current state of your app as a whole is.
Bound property values
A component property value can be bound to any one of the variables described in the previous section. For example, a Title component's text content could be bound to the
currentUser.name app variable, and a Button's text color could be bound to the
$colorInformative theme variable. You can even bind a property value to a different component property value.
The value type for a property can be changed via the dropdown to the left of the property value input, as seen in the above screenshot.
To learn more about bindings, please read the binding data guide.
Bindings can be created by changing a property's value type to one of the variable types, or in the case of style properties, via the link icon next to the input field.
Some variables such as theme variables and certain system variables like the current OS never change during app runtime, while others such as page variables are expected to change.
When a variable changes, any bound component properties will change automatically. Similarly, if the bound variable is a dynamic one, changes to the component property (by user interaction in the case of an input property, or by using Set component property) will update the bound variable.
However, if you have bound a non-dynamic variable such as a system variable to a component property, the bound variable will not be updated. Rather, the component state will be out of sync with the expected binding until the variable changes again – and if it does not, the out of sync state will not be resolved.
Generally speaking, you should never have to modify component properties directly via the Set component property flow function (or styles via Set component styles), but instead bind the property to a variable that you then change with the appropriate flow functions.
Non-dynamic variables and input properties
You can bind non-dynamic variables to an input-type component property, but changes will not propagate back to the variable.
For example, the Value of your Input field can be bound to
systemVars.dimensions.viewport.width, which will cause the input field to initialize with the current viewport width.
Since the bound variable is a system varaible, editing the input field will not change the value of
However, if the user resizes the browser window, the variable does change, and everything bound to it is refreshed, overriding whatever the user had written in the field.
Property values bound to formulas
When a component property is bound to a formula, the formula is re-evaluated automatically whenever any one of its dependent variables changes. Thus, if you have bound your text component to a formula that formats your
data.Order.createdAt date field into a human-readable format, you don't have to implement any extra logic – every time
data.Order.createdAt gets a new value, the formula is re-evaluated and the binding is updated.
Note that formula bindings are always non-dynamic. Thus, even if you bind
pageVars.currentInputValue via a formula to your input field, changes made by the user will not affect the variable.