Repository: streamlit/streamlit

Issue:
Button / `st.session_state` bug introduced with 1.20?
### Checklist

- [X] I have searched the [existing issues](https://github.com/streamlit/streamlit/issues) for similar issues.
- [X] I added a very descriptive title to this issue.
- [X] I have provided sufficient information below to help reproduce this issue.

### Summary

It looks like `st.session_state` misbehaves since 1.20, at least when used together with an infinite loop.
Buttons on_click functions are no more executed a second time.

1) With version **1.19 it is OK**: clicking buttons it reacts correctly resetting and descreasing the respective counter.
2) With version 1.20+ a second click on a button is not recognized anymore, and the `st.session_state` dictionary complains that the `counter` key does not exist.

Was there a features change in 1.20 to justify this behavior?

### Reproducible Code Example

```Python
import streamlit as st
import time

if "button" not in st.session_state:
	st.session_state["button"] = "----"
if "counter" not in st.session_state:
	st.session_state["counter"] = 0

def btn1_click():
	st.session_state["counter"] = 10
	st.session_state["button"] = "Btn1"


def btn2_click():
	st.session_state["counter"] = 20
	st.session_state["button"] = "Btn2"

cols = st.columns(3)
with cols[0]:
	st.button("Btn1", on_click=btn1_click)
with cols[1]:
	st.button("Btn2", on_click=btn2_click)
with cols[2]:
	ph = st.empty()

i = 0
while True:
	time.sleep(.1)
	
	if st.session_state["counter"] > 0:
		st.session_state["counter"] -= 1
		if st.session_state["counter"] == 0:
			st.session_state["button"] = "----"
	
	with ph.container():
		st.write(st.session_state)
	
	i+=1
	print(f"{i: 4d} button {st.session_state['button']} => counter {st.session_state['counter']}")
```


### Steps To Reproduce

Install streamlit 1.19, then 1.20.
Clicking each button you see that the behavior is completely different, because they stop working after the first click for the newest libraries. 

### Expected Behavior

_No response_

### Current Behavior

_No response_

### Is this a regression?

- [X] Yes, this used to work in a previous version.

### Debug info

- Streamlit version: 1.19 - 1.20+
- Python version: 3.8
- Operating System: Ubuntu
- Browser: Firefox, Brave, Edge
- Virtual environment: venv


### Additional Information

_No response_

### Are you willing to submit a PR?

- [ ] Yes, I am willing to submit a PR!


Discussion:
Thanks, @Nemecsek, for opening this issue!

I was able to reproduce this behavior and confirm it.

After some investigation, I found that this is related to the `fastRerun` config option, which recently changed the default to `true`. 

So the workaround for this issue would be to set the `fastRerun` config option in `config.toml` to `false`. 

Please see more details here: https://docs.streamlit.io/library/advanced-features/configuration

Resolving patch:
diff --git a/lib/streamlit/runtime/state/session_state.py b/lib/streamlit/runtime/state/session_state.py
--- a/lib/streamlit/runtime/state/session_state.py
+++ b/lib/streamlit/runtime/state/session_state.py
@@ -493,8 +493,8 @@ def on_script_will_rerun(self, latest_widget_states: WidgetStatesProto) -> None:
         Update widget data and call callbacks on widgets whose value changed
         between the previous and current script runs.
         """
-        # Update ourselves with the new widget_states. The old widget states,
-        # used to skip callbacks if values haven't changed, are also preserved.
+        # Clear any triggers that weren't reset because the script was disconnected
+        self._reset_triggers()
         self._compact_state()
         self.set_widgets_from_proto(latest_widget_states)
         self._call_callbacks()


Test patch: