In version 1,
- Click the button
- Page reloads with the button widget returning True
-
st.session_state.x
is shown twice (not yet changed) - Enter the conditional
if submitted
and the value is incremented -
st.session_state.x
is shown again, reflecting the incremented value
In version 1, with reload:
- Click the button
- Page reloads with the button widget returning True
-
st.session_state.x
is shown twice (not yet changed) - Enter the conditional
if submitted
and the value is incremented - Rerun the page (which happens so fast you don’t see point 3.
- Page now loads with the button widget returning False
- You get
st.session_state.x
shown all three times, reflecting the incremented value
In version 2,
- Click the button
- Page begins reloading but before it starts executing, it is prefixed with the callback.
- Hence the value is incremented
- Then the rest of the page loads (button happens to be True at this point, but not relevant)
- You get
st.session_state.x
shown all three times, reflecting the incremented value
The key is that the callback happens before the page loads. If you use the if st.button(...)
construct, then the code nested in the conditional doesn’t execute until you’ve reloaded the page to that point. If you have anything on the page before the button that needs to use the incremented value, you need the experimental rerun in this case. If you were to only use the value after the button, you could get away without the experimental rerun.
Note: You can use containers to change the order things display to be different from the order they appear in code. It’s the order in code that dictates the need for the rerun or not (if not using a callback). Hence you could code a button at the top of your script, but display it at the bottom with a slick arrangement of containers.