reflex-dev / reflex

🕸️ Web apps in pure Python 🐍
https://reflex.dev
Apache License 2.0
20.14k stars 1.16k forks source link

When rx.cond and rx.accordian are used together, the open accordian is closed when the `value` prop in accordion Item is not set after applying deltas. #3086

Open Evenzel opened 6 months ago

Evenzel commented 6 months ago

Describe the bug When rx.cond and rx.accordian are used together, the open accordian is closed when rx.form is submitted.

To Reproduce


import reflex as rx

class TestState(rx.State):
    result: dict = {}

    def handle_submit(self, data):
        self.result = data

@rx.page(route="/")
def index():
    return rx.cond(
        TestState.is_hydrated,
        rx.vstack(
            rx.form(
                rx.vstack(
                    rx.accordion.root(
                        rx.accordion.item(
                            header='test',
                            content=rx.hstack(
                                rx.select(
                                    ["Yes", "No"],
                                    placeholder="Select an option",
                                    name="test_form",
                                    font_size="1em",
                                ),
                                rx.button("Submit", type_="submit"),
                            ),
                        ),
                        collapsible=True,
                    ),
                ),
                on_submit=TestState.handle_submit,
            ),
            rx.text(TestState.result['test_form'])
        ),
        rx.chakra.spinner(),
    )

app = rx.App()

Expected behavior accordian should not be closed.

Screenshots 1) Before submit image

2) After submit image

Specifics (please complete the following information):

Additional context Add any other context about the problem here.

ElijahAhianyo commented 6 months ago

I've played around this a bit and I suspect this might be a radix bug(would need further investigations to conclude). For AccordionItem, we generate a random value for the value prop which is required by radix and is used in controlling the item based on the trigger. For some weird reason when state value changes (or deltas are applied after an event handler is triggered), the accordion item doesn't maintain its state(open/closed). This would require some further investigations into how radix treats the value prop since they don't seem to render the value prop in the DOM. But this behavior seems to show up when the accordion is in a conditional.

Even without the form, this is enough to repro:


import reflex as rx

class TestState(rx.State):
    val : bool = True
    num: int = 0

    def increment(self):
        self.num += 1

@rx.page(route="/")
def index():
    return rx.cond(
        TestState.val,
        rx.vstack(
            rx.text(TestState.num),
            rx.button("incremment", on_click=TestState.increment),
            rx.vstack(
                rx.accordion.root(
                    rx.accordion.item(
                        header='test',
                        content=rx.hstack(
                            rx.select(
                                ["Yes", "No"],
                                placeholder="Select an option",
                                name="test_form",
                                font_size="1em",
                            ),
                        ),
                    ),
                    collapsible=True,
                ),
            ),
        ),
        rx.chakra.spinner(),
    )

A workaround will be to provide a value for the accordion item:

...
rx.accordion.root(
    rx.accordion.item(
          header='test',
          content=rx.hstack(
                            rx.select(
                                ["Yes", "No"],
                                placeholder="Select an option",
                                name="test_form",
                                font_size="1em",
                            ),
                            rx.button("Submit", type_="submit"),
          ),
         value="item1" # provide a value 
   ),
  collapsible=True,
),
Anga205 commented 6 months ago

A workaround will be to provide a value for the accordion item:

does this have to be a predefined state value or can it just be any old string, i ask because you defined value = "item1" but item1 was never mentioned anywhere in the provided snippet

ElijahAhianyo commented 6 months ago

A workaround will be to provide a value for the accordion item:

does this have to be a predefined state value or can it just be any old string, i ask because you defined value = "item1" but item1 was never mentioned anywhere in the provided snippet

Yes, value can be any arbitrary string

Lendemor commented 6 months ago

Since the UUID is generated on the frontend rather than during compilation, state changes which trigger a re-render will generate a new UUID, so the currently open tabs don't match anymore.