State
State is organized as a key-value store. In order to associate a state with a session accross multiple requests, a token is created. The next request of the same session must include the state token, which will then be used to resolve the associated state.
By default the JWTStateResolver
is used, which transforms the state into a JWT token, making the server side entirely stateless.
This is handled by the StateResolver
of the App
(default: default_state_resolver
).
Conventions
To handle the livetime of state prefixes are used.
- no prefix is global state
#
prefix is temporary state, which will be discarded if no longer used!
prefix is protocol state, which holds headers and the location (path + query string). This data will always be present for the components, but is only associated with the token, if actually used
with Components
There are helpers for defining and using states in Components. These let you define state variables and access them almost like they were native fields.
local_state
- which is confined to a single component instancefrom typing import Annotated from rxxxt import Component, event_handler, VEl, Element, local_state class InputExample(Component): text = local_state(str) @event_handler(debounce=500) def on_input(self, value: Annotated[str, "target.value"]): self.text = value def render(self) -> Element: return VEl.input(oninput=self.on_input, type="text", value=self.text)
global_state
- which is shared accross the entire applicationfrom typing import Annotated from rxxxt import Component, event_handler, VEl, Element, global_state class InputExample(Component): text = global_state(str) @event_handler(debounce=500) def on_input(self, value: Annotated[str, "target.value"]): self.text = value def render(self) -> Element: return VEl.input(oninput=self.on_input, type="text", value=self.text)
context_state
- which is shared accross components down the tree from the first component that uses itlocal_state_box
- which is confined to a single component instance, but requires manual updatesfrom typing import Annotated from rxxxt import Component, event_handler, VEl, Element, local_state_box class InputExample(Component): text = local_state_box(str) @event_handler(debounce=500) def on_input(self, value: Annotated[str, "target.value"]): self.text.value = value self.text.update() def render(self) -> Element: return VEl.input(oninput=self.on_input, type="text", value=self.text.value)
global_state_box
- which is shared accross the entire application, but requires manual updatesfrom typing import Annotated from rxxxt import Component, event_handler, VEl, Element, global_state_box class InputExample(Component): text = global_state_box(str) @event_handler(debounce=500) def on_input(self, value: Annotated[str, "target.value"]): self.text.value = value self.text.update() def render(self) -> Element: return VEl.input(oninput=self.on_input, type="text", value=self.text.value)
context_state_box
- which is shared accross components down the tree from the first component that uses it, but requires manual updates