FastUI
FastUI copied to clipboard
Infinite loop when using ServerLoad without components parameter.
I mentioned this at #123.
Example code:
from __future__ import annotations as _annotations
import random
import time
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
from fastui import AnyComponent, FastUI, prebuilt_html
from fastui import components as c
from fastui.events import GoToEvent, PageEvent
def Master(*components: AnyComponent, title: str | None = None) -> list[AnyComponent]:
return [
c.PageTitle(text="Lotto Numbers Generator"),
c.Navbar(
title="Still Lotto Numbers Generator",
title_event=GoToEvent(url="/"),
),
c.Page(
components=[
*((c.Heading(text=title),) if title else ()),
*components,
],
),
]
app = FastAPI()
@app.get("/api/", response_model=FastUI, response_model_exclude_none=True)
def components_view() -> list[AnyComponent]:
return Master(
c.Div(
components=[
c.Heading(text="Lotto Numbers Generator", level=2),
c.Paragraph(text="Generate lotto numbers for your next game."),
c.Button(text="Generate a lotto number!", on_click=PageEvent(name="add-number")),
c.Div(
components=[
c.ServerLoad(
path="/add-number",
load_trigger=PageEvent(name="add-number"),
),
],
class_name="py-2",
),
],
class_name="border-top mt-3 pt-1",
),
title="Quite simple and Understandable Example",
)
@app.get("/api/add-number", response_model=FastUI, response_model_exclude_none=True)
async def modal_view() -> list[AnyComponent]:
time.sleep(0.5)
return [
c.Paragraph(
text=f"Your lotto number is {random.randint(1, 99)}!",
),
c.ServerLoad(
path="/add-number",
load_trigger=PageEvent(name="add-number"),
),
]
@app.get("/{path:path}")
async def html_landing() -> HTMLResponse:
"""Simple HTML page which serves the React app, comes last as it matches all paths."""
return HTMLResponse(prebuilt_html(title="FastUI Demo"))
If you navigate to /
, you'll see the ServerLoad
event keeps triggering even fi you don't click the button.
It seems the problem is here:
https://github.com/pydantic/FastUI/blob/cec25c61a7cc5a716d05d21039f95be3e8dac0e8/src/npm-fastui/src/components/ServerLoad.tsx#L15C14-L23
Maybe the condition should depend on loadTrigger
and not on components
:
export const ServerLoadComp: FC<ServerLoad> = ({ path, components, loadTrigger, sse }) => {
if (loadTrigger) {
return <ServerLoadDefer path={path} components={components ?? []} loadTrigger={loadTrigger} sse={sse} />
} else if (sse) {
return <ServerLoadSSE path={path} />
} else {
return <ServerLoadFetch path={path} />
}
}
I'll look soon.