I think the loop solution is the way to go in these cases… but I personally don’t like it and it conflicts with the way widgets work as you pointed out. st.rerun as suggested by @Marc would solve this. Here is a link to a feature request for st.rerun: https://github.com/streamlit/streamlit/issues/168
And here is a gist for a simple dashboard on top of st.rerun and Session State gists. The latter is a way to allow you to persist state across re-runs: https://gist.github.com/monchier/4ba216cc9168a7d2bea7f3f31a1c4491
These are not part of Streamlit yet, but you are free to get the gists and play with them.
I am using the st.rerun and a somewhat similar development of the Session State gists for a multi page dashboard and query tool we deployed to business users this week. I wrapped the gists into a StreamlitPage base class that takes care of a bunch of other setup, navigation, and logging and from which all my application pages are subclassed. It all works well, but you do need to be careful about exactly when you call st.rerun.
I haven’t implemented a continuous loop update yet. What I do for now is use a cached function to get the data and supply a timestamp parameter that is quantized to whatever interval is convenient (we use 5 minutes at present). Then repeat runs on the page usually use the cache and the user only sees occasional data retrieval hits. For historical periods (not including the current day) the timestamp is always None, so the data is always cached.