Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Session State

State is the base class for application state. It is a PropertyHost: a plain object whose fields are reactive Property and Signal handles.

Declaring state

The simplest form declares fields inside __init__:

import streamlit_canary as sc


class State(sc.State):
    def __init__(self):
        super().__init__()
        self.count = sc.Property(0)
        self.name = sc.Property('')


state = State()

A field may also be declared by annotation. PropertyHost builds one handle per instance:

class State(sc.State):
    count: sc.Property[int] = 0
    name: sc.Property[str]
    reloaded: sc.Signal
  • Property[int] with a class-body value uses that value as the default.
  • Without a class-body value the property starts as sc._undefined (see Special markers).
  • Signal declares no payload; Signal[int] declares one positional payload.

Do not declare a Property instance at class level unless the state class has a single instance. Class-level properties are shared between instances.

Reading and writing

state.count.get()        # 0
state.count.set(1)       # 1, emits state.count.on_change
state['count']           # 1
state['count'] = 2       # 2
state['on_count']        # state.count.on_change

state.count += 1 is not supported by the property object itself. Use the subscript form, which the runtime maps to get and set:

state['count'] += 1

Reacting to changes

@state.count.on_change
def _():
    print('count is now', state.count.get())

A handler may receive the property handle or its current value:

@state.count.on_change.partial(sc._self)
def _(prop):
    print(prop.get())

@state.count.on_change.partial(sc._value)
def _(value):
    print(value)

Binding

A derived value is created with sc.bind:

double = sc.bind(state.count, lambda n: n * 2)

A two-way binding is created with sc.bbind:

sc.NumberInput('Count', sc.bbind(state.count))

See The Event Driven System for the full explanation of triggers, multiple sources, and default=.

Versioning

State tracks a schema version:

class State(sc.State):
    __version__ = 2
    ...

or pass it explicitly:

state = State(version=2)

The version is currently metadata (state.version). It gives the app a place to detect an incompatible state layout and rebuild it.

Lifetime

State lives in the server process for the life of a session. Because the app function does not rerun, a value written in one handler is still there in the next handler.

This also means that state is not rebuilt from the script. If you need a value to reset, reset it explicitly:

state.count.set(0)

Relationship to Streamlit’s session_state

State replaces st.session_state for V3 apps. The two are not synchronized. A V3 app should keep its state in State and pass it to handlers by closure, or store it on the app object.