When more than one widget is made with the same key, there is a duplicate widget id error, and this is expected. However, when a placeholder is made and updated with the same widget twice, the error is still raised, despite there technically only being one widget. Here is the example:
import streamlit as st
import time
placeholder = st.empty()
while True:
placeholder.text_area("Hi", key="placeholder")
time.sleep(5)
I tried amending this by deleting from the cache but the same thing happens:
import streamlit as st
import time
placeholder = st.empty()
while True:
if "placeholder" in st.session_state:
del st.session_state["placeholder"]
placeholder.text_area("Hi", key="placeholder")
time.sleep(5)
This is the pattern that I use in a dashboard Iām making, and itās important that I set a key, because I want to get the value in a callback function and I donāt believe there is another way to pass a widgetās value into its callback. I want to use a callback to leverage the āon changeā nature of it, rather than detect a change with the returned string of a text_area, although that may be the only way I can work around this.
I am afraid the widget state persists in some way until the script is run again and thatās why you canāt instantiate another one with the same key.
You might use a UUID as the key but if I am right then that would be a memory leak, so donāt do it unless you can ensure the number of iterations has an upper bound.
placeholder.text_area("Hi", key=uuid.uuid4())
OTOH do you really need a loop and replacing the widget? This code seems to achieve the same.
The loop fetches data from databases, would I be able to update my dashboard in your suggestion?
Edit: logically, it seems like I would be able to. Wouldnāt this be reloading all my other UI though?
I also just thought of assigning a random key and passing that in the callback, but I might not have an upper bound and did not consider the memory usage
Didnāt try any code myself, however just a long shot regarding the memory leak: Did you try to garabage collect in between script runs? Maybe a simple gc.collect() will help?
Other than that, I believe currently the only solution is to st.experimental_rerun(). Unfortunatelly, there is currently no way to only update a single widget.
I donāt see why my suggestion of rerun the app instead of having a loop would not work for you. Reloading the UI should not be a problem, that is how streamlit is designed to work.
That is a problem when you have elements that take a long time to render, like complex charts with lots of data. But replacing widgets forever willl leak unbounded amounts of memory.
Maybe a mixed approach, where a rerun is triggered every now and then to free memory would work. Or being creative with the dashboard design: simpler widgets are faster to render and there can be different views so that not everything needs to be on sight at the same time.