You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Several components trigger REST fetches during render (component body) instead of in effects. In a signals architecture this is a footgun: every fetch writes a signal (LOADING → SUCCESS), every write re-renders, and the body fires the fetch again. Depending on the guard, the result is an infinite request/render loop (frozen UI) or stale data.
Incident that surfaced this
After the start-form flow became functional (#90), starting a process from the task list froze the whole UI until reload: StartProcessList fetched list_startable unguarded plus the definition/start-form chain in the component body — a self-sustaining loop of requests and re-renders pegging the main thread. The loop had been latent; it only closed once the chain stopped crashing halfway.
Fix pattern applied there (suggested as the general convention):
if (!signal.value) guard → bounded, but stale. Fires only while the signal is empty — so it never refetches when the parameter changes. Example: components/TaskForm.jsxRenderedFallbackForm (if (!state.api.task.rendered_form.value)) keeps showing the previous task's generated form when switching tasks. Same pattern in pages/TaskForm.jsx and pages/Dashboard.jsx.
Compare-signal guard (last_fetched_filter, loaded_for) → works, but ad-hoc.pages/Processes.jsx uses hand-rolled cache-key signals where effect deps would express the same thing declaratively.
Suggested cleanup
Establish as convention: data fetching lives in useEffect with the fetch inputs as dependencies — never in the component body. Guards on signal emptiness are not a substitute, since they break parameter-driven refetches.
Migrate the pattern-2 and pattern-1 sites; pattern-3 sites can stay but are candidates for simplification.
Summary
Several components trigger REST fetches during render (component body) instead of in effects. In a signals architecture this is a footgun: every fetch writes a signal (
LOADING→SUCCESS), every write re-renders, and the body fires the fetch again. Depending on the guard, the result is an infinite request/render loop (frozen UI) or stale data.Incident that surfaced this
After the start-form flow became functional (#90), starting a process from the task list froze the whole UI until reload:
StartProcessListfetchedlist_startableunguarded plus the definition/start-form chain in the component body — a self-sustaining loop of requests and re-renders pegging the main thread. The loop had been latent; it only closed once the chain stopped crashing halfway.Fix pattern applied there (suggested as the general convention):
Guard taxonomy found in the codebase
StartProcessList(fixed as part of Start process via start form is broken end-to-end (undefined fetch, crash on non-embedded forms, submit disabled) #90's flow);pages/Tasks.jsxtask-list fetching around line 44 deserves a close look (guard logic is implicit).if (!signal.value)guard → bounded, but stale. Fires only while the signal is empty — so it never refetches when the parameter changes. Example:components/TaskForm.jsxRenderedFallbackForm(if (!state.api.task.rendered_form.value)) keeps showing the previous task's generated form when switching tasks. Same pattern inpages/TaskForm.jsxandpages/Dashboard.jsx.last_fetched_filter,loaded_for) → works, but ad-hoc.pages/Processes.jsxuses hand-rolled cache-key signals where effect deps would express the same thing declaratively.Suggested cleanup
useEffectwith the fetch inputs as dependencies — never in the component body. Guards on signal emptiness are not a substitute, since they break parameter-driven refetches.pages/TaskForm.jsxappears to be a legacy duplicate ofcomponents/TaskForm.jsx(still contains the oldformKey.substring(13)logic, cf. EmbeddedHtmlTaskForm: hardcoded substring(13) breaks embedded:deployment: forms and non-root context paths #96) — if it is unrouted dead code, deleting it removes several occurrences at once.