Base Vars
Vars are any fields in your app that may change over time. A Var is directly rendered into the frontend of the app.
Base vars are defined as fields in your State class.
They can have a preset default value. If you don't provide a default value, you must provide a type annotation.
AAPL
Current Price: $150
Change: 4%
In this example ticker and price are base vars in the app, which can be modified at runtime.
Accessing state variables on different pages
State is just a python class and so can be defined on one page and then imported and used on another. Below we define TickerState class on the page state.py and then import it and use it on the page index.py.
# state.py
class TickerState(rx.State):
ticker: str = "AAPL"
price: str = "$150"# index.py
from .state import TickerState
def ticker_example():
return rx.center(
rx.vstack(
rx.heading(TickerState.ticker, as_="h2", size="3"),
rx.text(f"Current Price: {TickerState.price}", font_size="md"),
rx.text("Change: 4%", color="green"),
),
)Changing Defaults
A state var is a descriptor on its state class, so assigning to it through the
class raises TypeError instead of replacing the var. To change a var's default,
call set_default on the var's field with either a default value or a
default_factory function:
import time
class WatchlistState(rx.State):
ticker: str = "AAPL"
symbols: list[str] = []
opened_at: float = 0.0
WatchlistState.__fields__["ticker"].set_default("MSFT")
WatchlistState.__fields__["symbols"].set_default(["AAPL", "MSFT"])
WatchlistState.__fields__["opened_at"].set_default(default_factory=time.time)The default applies to values not yet stored on an instance, which includes
every new session and reset(). Values already stored on an instance stay the
same. Pass exactly one of default and default_factory; a default_factory
is called for each new instance. set_default copies a mutable default, such
as a list, when you set it and gives each instance its own copy, so sessions
never share it and later changes to the value you passed do not reach the
default. It does not check the value against the var's annotation. A browser
storage var keeps its storage name and options only with a storage value as its
default, such as rx.LocalStorage("dark", name="theme"). Given a plain string,
a var annotated str becomes an ordinary var, and one annotated with a storage
type, such as rx.LocalStorage, stays in browser storage under the default key
and options.
An inherited var belongs to the state that declared it, so changing its field
also changes the default for every state that inherits it. Each generated
ComponentState class owns copies of its fields, allowing
get_component to configure defaults
independently for each component.
In tests, patch the field rather than the class attribute, which raises the same
TypeError:
from unittest import mock
with mock.patch.object(WatchlistState.__fields__["ticker"], "default", "MSFT"):
...Declare class-level configuration, such as a client or a lock, as a ClassVar.
It stays an ordinary class attribute, so assigning it through the class is
allowed, and it is never copied for each instance. Each backend worker process
holds its own value, though, so a lock only serializes the sessions on its own
worker. A value set at import time, such as at module level, starts the same in
every worker, but a change made after the workers start, such as in an event
handler, never reaches the other workers. Keep a value that sessions must share
at runtime in an rx.SharedState or an
external store.
Backend-only Vars
Any Var in a state class that starts with an underscore (_) is considered backend
only and will not be synchronized with the frontend. Data associated with a
specific session that is not directly rendered on the frontend should be stored
in a backend-only var to reduce network traffic and improve performance.
They have the advantage that they don't need to be JSON serializable, however they must still be pickle-able to be used with redis in prod mode. They are not directly renderable on the frontend, and may be used to store sensitive values that should not be sent to the client.
For example, a backend-only var is used to store a large data structure which is then paged to the frontend using cached vars.
Read and write a backend var through a state instance, such as self._token.
Reading MyState._token through the class returns its field descriptor, whose
default_value() method returns the default (a fresh copy if it is mutable). Use
it to build the UI from a constant, such as
rx.foreach(MyState._options.default_value(), rx.text) for a backend var
_options. Assigning to MyState._token raises TypeError: change its default
through its field as described above.
For class-level configuration, declare a ClassVar instead:
from typing import ClassVar
class MyState(rx.State):
_endpoint: ClassVar[str] = "https://example.com/api"
_token: str = ""
MyState._endpoint = "https://example.com/v2"ClassVar values are ordinary class attributes and are not part of session state.
Reading one on the class returns the plain value, and an object that cannot be
copied, such as a client or lock, is shared rather than copied for each instance.
Each backend worker holds its own value, as described under
Changing Defaults.
Page 1 / 10
Page Size
_backend[0] = 84
_backend[1] = 64
_backend[2] = 5
_backend[3] = 87
_backend[4] = 30
_backend[5] = 96
_backend[6] = 68
_backend[7] = 42
_backend[8] = 54
_backend[9] = 68
Using rx.field / rx.Field to improve type hinting for vars
When defining state variables you can use rx.Field[T] to annotate the variable's type. Then, you can initialize the variable using rx.field(default_value), where default_value is an instance of type T.
This approach makes the variable's type explicit, aiding static analysis tools in type checking. In addition, it shows you what methods are allowed to modify the variable in your frontend code, as they are listed in the type hint.
Below are two examples:
import reflex as rx
app = rx.App()
class State(rx.State):
x: rx.Field[bool] = rx.field(False)
def flip(self):
self.x = not self.x
@app.add_page
def index():
return rx.vstack(
rx.button("Click me", on_click=State.flip),
rx.text(State.x),
rx.text(~State.x),
)Here State.x, as it is typed correctly as a boolean var, gets better code completion, i.e. here we get options such as to_string() or equals().
import reflex as rx
app = rx.App()
class State(rx.State):
x: rx.Field[dict[str, list[int]]] = rx.field(default_factory=dict)
@app.add_page
def index():
return rx.vstack(
rx.text(State.x.values()[0][0]),
)Here State.x, as it is typed correctly as a dict of str to list of int var, gets better code completion, i.e. here we get options such as contains(), keys(), values(), items() or merge().