Unexpected Server Errors #7730
|
Hi, I've been running into the following errors: Both errors come about when adding more components to my app. I use quite a few component states. An example of a setup would be: from typing import Callable
import reflex as rx
cancel_button = rx.button(
"Cancel",
type="button",
color_scheme="gray",
variant="outline",
)
def popover_form(
trigger: rx.Component,
form_content: rx.Component,
submit_button: rx.Component,
on_form_submit_event: Callable | list[Callable],
):
return PopoverForm.create(
trigger_component=trigger,
form_content=form_content,
submit_button=submit_button,
on_form_submit_event=on_form_submit_event,
)
class PopoverForm(rx.ComponentState):
is_open: bool = False
@rx.event
def toggle_open(self):
self.is_open = not self.is_open
@classmethod
def get_component(
cls,
trigger_component: rx.Component,
form_content: rx.Component,
submit_button: rx.Component,
on_form_submit_event: Callable | list[Callable],
) -> rx.Component:
on_submit = []
if isinstance(on_form_submit_event, list):
on_submit.extend(on_form_submit_event)
else:
on_submit.append(on_form_submit_event)
on_submit.append(cls.toggle_open)
return rx.popover.root(
rx.popover.trigger(trigger_component, width="100%"),
rx.popover.content(
rx.form(
rx.vstack(
form_content,
rx.hstack(
submit_button,
rx.popover.close(cancel_button),
margin_top="2rem",
)
),
on_submit=on_submit,
reset_on_submit=True,
),
min_width="max-content",
width="20rem",
),
on_open_change=cls.toggle_open,
open=cls.is_open,
)
class ProjectDropdownMenu(rx.ComponentState):
is_open: bool = False
@rx.event
def set_is_open(self, is_open: bool):
self.is_open = is_open
@classmethod
def create_option(cls, on_form_submit: list[Callable] = []):
return popover_form(
trigger=rx.button("Create"),
form_content=rx.input(placeholder="Name"),
submit_button=rx.button("Submit"),
on_form_submit_event=on_form_submit,
)
@classmethod
def edit_option(cls, on_form_submit: list[Callable] = []):
return popover_form(
trigger=rx.button("Edit"),
form_content=rx.input(placeholder="Name"),
submit_button=rx.button("Save"),
on_form_submit_event=on_form_submit,
)
@classmethod
def duplicate_option(cls, on_click: list[Callable] = []):
return rx.popover.root(
rx.popover.trigger(rx.button("Duplicate"), cursor="pointer"),
rx.popover.content(
rx.vstack(
rx.text(
"Warning: This will duplicate everything under this project"
),
rx.text("Are you sure you want to duplicate"),
rx.hstack(
rx.popover.close(rx.button("Duplicate", on_click=on_click)),
rx.popover.close(cancel_button),
)
)
)
)
@classmethod
def delete_option(cls, on_click: list[Callable] = []):
return rx.popover.root(
rx.popover.trigger(
rx.button("Delete", color_scheme="red"), cursor="pointer"
),
rx.popover.content(
rx.vstack(
rx.text("Warning: This will delete EVERYTHING."),
rx.text("Are you sure you want to delete this project?"),
rx.hstack(
rx.popover.close(cancel_button),
rx.popover.close(
rx.button(
"Delete",
on_click=on_click,
color_scheme="red",
)
)
)
)
)
)
@classmethod
def get_component(
cls,
has_create: bool = True,
has_edit: bool = True,
has_duplicate: bool = True,
has_delete: bool = True,
on_change: list[Callable] = [],
) -> rx.Component:
dropdown_options: list[rx.Component] = []
if has_create:
dropdown_options.append(cls.create_option(on_form_submit=on_change))
if has_edit:
dropdown_options.append(cls.edit_option(on_form_submit=on_change))
if has_duplicate:
dropdown_options.append(cls.duplicate_option(on_click=on_change))
if has_delete:
dropdown_options.append(cls.delete_option(on_click=on_change))
return rx.popover.root(
rx.popover.trigger(
rx.button(
rx.icon("settings_2", size=18),
padding="revert-layer",
variant="outline",
)
),
rx.popover.content(
rx.vstack(
*dropdown_options,
spacing="1",
),
padding="0.5rem",
),
default_open=False,
open=cls.is_open,
on_open_change=cls.set_is_open,
)
project_dropdown_menu = ProjectDropdownMenu.createThe number of components like My questions are:
|
Replies: 1 comment 1 reply
|
Yes, it comes from the number of Up to 0.9.x the frontend wraps the whole app in a nested provider pair for each substate ( 0.10.0 cut the server tree to one provider per substate (#7369), and 0.10.1 replaced the nested providers with a single store context on both server and client (#7441, template in v0.10.1). The depth no longer grows with the number of substates, so upgrading to 0.10.1 should fix it. Your post does not say which version you are on. If it still happens on 0.10.1, the output of To check this I compiled your code unchanged (plus 23 pages with 7 That is the provider tree on its own. In the real app the root layout and the page share the same stack, so the limit there is lower than these numbers. For the third question, the usage is fine, but a state class per menu is more than this needs. The outer popover's class MenuState(rx.State):
open_key: str = ""
@rx.event
def set_open(self, key: str, is_open: bool):
self.open_key = key if is_open else ""
@rx.event
def close(self):
self.open_key = ""
def popover_form(key: str, trigger, form_content, submit_button, on_submit=()):
return rx.popover.root(
rx.popover.trigger(trigger, width="100%"),
rx.popover.content(
rx.form(
rx.vstack(form_content, rx.hstack(submit_button, rx.popover.close(cancel_button))),
on_submit=[*on_submit, MenuState.close],
reset_on_submit=True,
),
),
open=MenuState.open_key == key,
on_open_change=lambda is_open: MenuState.set_open(key, is_open),
)The same 23 × 7 app written this way compiles to 6 substates in total on 0.9.13 and 0.10.1, and the generated JS passes the key and the open flag as expected. I only compiled it. I have not clicked through it in a browser. |
Yes, it comes from the number of
ComponentStateinstances. Every call toProjectDropdownMenu.create()defines a new state class (ProjectDropdownMenu_n1,_n2, ...), and the twopopover_formcalls inside it define two morePopoverForm_nXclasses (ComponentState.create). They all land in one app-wide state tree, so a page with a single menu still renders the providers for every menu on all 23 pages. With 23 pages × 7 menus × 3 classes that is 483 substates.Up to 0.9.x the frontend wraps the whole app in a nested provider pair for each substate (
StateProviderin v0.9.13). React's server renderer recurses once per level, and with a few hundred substates the dev server runs out of stack. When …