reflex icon indicating copy to clipboard operation
reflex copied to clipboard

`rx.input(value=State.nested.var)` is not updated when `nested` is set to a new object containing the same content.

Open abulvenz opened this issue 1 year ago β€’ 3 comments

Describe the bug We have some validation checks in setters that do not let through some changes from the frontend. Unfortunately the reload button does not reset the UI.

To Reproduce Steps to reproduce the behavior:

  • Use below app
  • Type an "a" into the input
  • Because your input is invalid, the state is not updated in the setter.
  • Click "Create new Object". This will overwrite the object in the state. # Here I would expect an update in the input.
  • The input still shows the old value, containing the "a".
  • Click "Create other Object". This time the input changes to "12345"
import reflex as rx

class Object(rx.Base):
    name: str = "1234"


class State(rx.State):
    """The app state."""
    message: str = "Default"
    object: Object = Object()

    def create_new_object(self):
        self.object = Object()
        self.message = self.object.name
        print(self.object.name)
    
    def create_new_object_2(self):
        self.object = Object(name="12345")
        self.message = self.object.name
        print(self.object.name)

    def set_name(self, value: str):
        if not "a" in value:
            self.object.name = value
            self.message = ""
        else:
            self.message="You can't use the letter 'a' in the name"

def index() -> rx.Component:
    return rx.container(
        rx.text(f"Your message: ", State.message), 
        rx.text(f"Object name: ", State.object.name),
        rx.input(value=State.object.name, on_change=State.set_name),
        rx.button("Create new object", on_click=State.create_new_object),
        rx.button("Create other object", on_click=State.create_new_object_2),
    )

app = rx.App()
app.add_page(index)

Expected behavior The input should show the variable value after pressing the button.

abulvenz avatar Jul 10 '24 13:07 abulvenz

I believe the issue is https://github.com/nkbt/react-debounce-input/issues/130

The internal state of the debounce is not getting updated because the bound state var does not actually change value [1].

I'm not sure if there's actually a fix we can make here πŸ˜”, but there are some potential workarounds:

  • set key prop on the rx.input to some value in the state that you increment/update when the object updates. This will force the input to be re-rendered with the correct value showing... Note however, reflex 0.5.6 currently has a bug where key is not passed through, so this would also need to be fixed in the framework before it's a real solution
  • trigger a state update in self.object.name to a different value, then set it back to the original value in the set_name function. The problem here is that the user gets their input swiped out from under them and reset to the last "valid" value, which is not a great UX.
  • in the create_new_object handler, if the new object name matches the current object name, first yield a state update that blanks out the self.object.name field, then update self.object to the new object. This is probably the cleanest workaround, but if these objects are getting created and assigned in multiple places, it's kind of a hassle, so you might need a helper function to handle the logic.

masenf avatar Jul 10 '24 20:07 masenf

Thanks for the fast reply @masenf . We have implemented the last workaround and yield the entire object as None and yield the new value afterwards. It causes a tiny flicker depending on the state size, but at least it works now as expected.

abulvenz avatar Jul 10 '24 20:07 abulvenz

We could try https://github.com/xnimorz/use-debounce which seems to be better maintained

benedikt-bartscher avatar Jul 11 '24 13:07 benedikt-bartscher