I appear to fundamentally misunderstand how Streamlit's forms and session_state
variable work. Form data is not inserted into the session_state
upon submit. However, submitting a second time inserts the data. Updating session_state
values always requires submitting the form 2 times.
I'd like to know
session_state
updates on submitEXAMPLE 1:
import streamlit as st
# View all key:value pairs in the session state
s = []
for k, v in st.session_state.items():
s.append(f"{k}: {v}")
st.write(s)
# Define the form
with st.form("my_form"):
st.session_state['name'] = st.text_input("Name")
st.form_submit_button("Submit")
When the page loads, the session state is empty: []
After submitting the form once, the session_state contains "name: "
. The key has been added, but not the value.
After pressing Submit
a second time, the session_state now contains "name: Chris"
EXAMPLE 2: Using a callback function
import streamlit as st
# View all key:value pairs in the session state
s = []
for k, v in st.session_state.items():
s.append(f"{k}: {v}")
st.write(s)
# Define the form
with st.form("my_form"):
def update():
st.session_state['name'] = name
name = st.text_input("Name")
st.form_submit_button("Submit", on_click=update)
When the page loads, the session state is empty: []
After submitting the form once, the session_state contains "name: "
. The key has been added, but not the value.
After pressing Submit
a second time, the session_state now contains "name: Chris"
The critical part to think about is: where are you writing session state values relative to where the widget is? In particular, you are accessing/displaying session state values before the widget.
Try this to see what's happening a bit clearer:
import streamlit as st
st.write(st.session_state)
with st.form('my_form'):
st.session_state.A = st.text_input('A')
st.text_input('B', key='B')
st.form_submit_button('Submit')
st.write(st.session_state)
You will note for widget A that session state does not update until after the widget. If you want to access data for widget A before widget A, then you end up with your "double submit" problem.
For widget B, you can see that session state is correct right away, even when accessed before the widget.
For a widget (outside of form), when a user makes a change:
If you have the output of a widget assign a value to session state instead of setting the key for the widget directly, then that output data cannot be updated until the widget function is executed again and can output that new value.
With a form, the same logic applies except that the new value is not registered until the submit button is clicked.