[resolved] Page reruns when widget clicked

Requested info for a debugging post:

  • Are you running your app locally or is it deployed? Just local
  • Share the full text of the error message. No error, just unexpected (or misunderstood) behavior
  • Share the Streamlit and Python versions Streamlit 1.38.0, Python 3.12.1

Working on an AI chatbot UI, trying to add a “solicit feedback” item to each answer. Something about how I’m adding the feedback widgets is resulting in this unusual behavior:

When a new message comes in, I both:

  • display the message and feedback widgets
  • add an item to st.session_state

On page [re]load, I load the old messages from st.session_state and generate a feedback widget.

This minimal reproduction demonstrates my situation:

import streamlit as st

def handle_feedback(id, feedback, note):
    st.toast(f"Got feedback for {id}: feedback:{bool(feedback)} note={note}")

def generate_feedback_area(id, state):
    st.header(f"{state} message: {id}")
    with st.popover("Submit Feedback"):
        st.caption(f"ID: {id}")
        feedback = st.feedback('thumbs',key=f"{id}-feedback")
        note = st.text_area("Note (optional)",key=f"{id}-note")
        if st.button("Submit",key=f"{id}-button"):
            handle_feedback(id=id, feedback=feedback, note=note)
    st.divider()

# Initialize chat history and load previous messages
if "messages" not in st.session_state:
    st.session_state.messages = []
else:
    for message in st.session_state.messages:
        generate_feedback_area(message,state='old')

#Allow user to add new message
if st.button("Add a message!",type='primary'):
    if st.session_state.messages:
        new_message = st.session_state.messages[-1] + 1
    else:
        new_message = 0
    generate_feedback_area(new_message,state='new')
    st.session_state.messages.append(new_message)

When you press “Add a message”, it creates a “new” message. However when you press any of the feedback items underneath it, the whole page re-runs, the newest message is redrawn as an old message, and the popover closes witch is a little disruptive- the user has to re-click in to finish submitting feedback.

Is there any way around this? To not re-run/refresh/redraw the page when a user clicks on a widget?

Well, the related pages suggested FAQ: How to prevent app reruns which suggests to use st.form which worked:

import streamlit as st

def handle_feedback(id, feedback, note):
    st.toast(f"Got feedback for {id}: feedback:{bool(feedback)} note={note}")

def generate_feedback_area(id, state):
    st.header(f"{state} message: {id}")
    with st.popover("Submit Feedback"):
        with st.form(key=f"{id}-form"):
            st.caption(f"ID: {id}")
            feedback = st.feedback('thumbs',key=f"{id}-feedback")
            note = st.text_area("Note (optional)",key=f"{id}-note")
            if st.form_submit_button("Submit"):
                handle_feedback(id=id, feedback=feedback, note=note)
    st.divider()

# Initialize chat history and load previous messages
if "messages" not in st.session_state:
    st.session_state.messages = []
else:
    for message in st.session_state.messages:
        generate_feedback_area(message,state='old')

#Allow user to add new message
if st.button("Add a message!",type='primary'):
    if st.session_state.messages:
        new_message = st.session_state.messages[-1] + 1
    else:
        new_message = 0
    generate_feedback_area(new_message,state='new')
    st.session_state.messages.append(new_message)
1 Like

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