Session state/ button interaction yields unexpected order

I want my button to toggle what it says depending on the session state, just like how a play button turns into pause after being clicked and back into play after being clicked again.

Here is the bare reproduction code I wrote to do so. Itโ€™s easiest if you just try and run the code because the behaviour is hard to explain.

import streamlit as st

# initialize recording_data as true
if "recording_data" not in st.session_state:
    st.session_state.recording_data = True

toggle_text = "Stop" if st.session_state.recording_data else "Start"
if st.sidebar.button(toggle_text):
    # flip recording_data
    st.session_state.recording_data = not st.session_state.recording_data
    
st.write(st.session_state)

Hitting the button switches recording_data, and hitting the button should also rerun the script, so I expect that since recording_data has been flipped, the text will also change.

Instead, the text changes every second time the button is pressed.

Printing out the session state is a bit revealing:

I expect two states:

  1. Text is โ€œStartโ€, st.session_state.recording_data = False
  2. Text is โ€œStopโ€, st.session_state.recording_data = True

But there are actually 4 states, in this order:

  1. Text is โ€œStartโ€, st.session_state.recording_data = False
  2. Text is โ€œStartโ€, st.session_state.recording_data = True
  3. Text is โ€œStopโ€, st.session_state.recording_data = True
  4. Text is โ€œStopโ€, st.session_state.recording_data = False

It seems to me like code in the button block is run after the site is reloaded, which is maybe a feature, not a bug, but is there a way to do what I want?

Seems like callback functions are what I need, as they execute when a button is pressed, and then the app is rerun, so if I put the change to session state in the callback all will be well, maybe

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.