Reactive Lifecycle, Render Loops, and Duplicate Handlers
A Reactive Web product configurator lets a user pick a country, a product, and a quantity, then see a price. Country is a Client Variable. A RegionList Block has an input parameter CountryId and an On Parameters Changed handler that calls the GetRegions server action. A PricePanel Block takes ProductId and Quantity and calls GetPrice in OnRender. While a user drags the quantity slider, about 40 value changes occur in 3 seconds, and the screen makes dozens of server calls and flickers. The browser console shows duplicate click handlers on the Add to cart button, growing by one after every render. A JavaScript node in OnReady attaches a click listener to that button. The team wants to add a loading spinner and increase the server timeout.
1. Explain which lifecycle events are firing and why the design produces repeated calls. What is wrong with calling GetPrice in OnRender?
Read the worked answer
OnRender runs after every render, and every render can be triggered by a client variable change. The quantity slider writes a Client Variable on each movement; each write re-renders the screen; the PricePanel's OnRender runs again and calls the GetPrice server action. That is tens of round trips in seconds. It is also a feedback risk: if the server action result updates a variable used in the render, the render triggers another render.
On Parameters Changed fires when input parameters change, including when the parent passes an expression that evaluates to a new value on each render. A server call inside that handler repeats per change and can loop if it writes a parent variable.
OnReady runs once after the first render, so it is the right place for one-time DOM setup, but not for per-render logic.
Why OnRender is wrong here: it is a post-render hook for measurement and DOM work, not a data-loading event. Loading data there couples network latency to rendering, makes the call count proportional to user interaction, and produces nondeterministic ordering. A spinner hides the symptom; a longer timeout makes failure slower and still leaves the calls.
2. Propose a fix for the slider and price updates, and for the duplicate click handlers, with trade-offs.
Read the worked answer
Price updates: stop calling the server on every change. Keep quantity in a Client Variable for immediate UI feedback, debounce the server call by roughly 300 to 500 ms after the last change, and call GetPrice once. Implement debounce in a small JavaScript node or with a client-side timer, and cancel the pending call when a new value arrives. If pricing rules are simple and stable, compute the price client-side and reconcile with the server at checkout; the trade-off is duplicated business logic that can drift from the server rules. Otherwise require an explicit Apply action, which is predictable but adds a click.
Remove the server call from OnRender entirely and load the initial price in OnReady or OnInitialize with the current product and quantity.
Duplicate handlers: attach the listener once in OnReady, keep a reference, and remove it in OnDestroy; guard against attaching twice. Better, replace raw DOM listeners with the platform's click event or an Event from the Block, so the framework manages binding and teardown. Never attach listeners in OnRender, because that runs after every render and is exactly why the count grows by one each time.
Trade-off: debounce adds a small perceived delay; a client formula risks rule drift; an explicit Apply is slower but easiest to reason about.
3. How would you make the Country to Region dependent dropdown correct without loops?
Read the worked answer
Separate initial load from change handling. In OnReady, load regions for the initial CountryId. On a country change, set CountryId, reset RegionId to Null, and load the new region list once. The reset matters: otherwise a region from the previous country remains selected and is submitted with the new country.
Guard On Parameters Changed. Compare the incoming CountryId with the last loaded value stored in a local variable; if it is Null or unchanged, skip the server call. This prevents re-fetching when the parent re-renders for an unrelated reason, which is the usual loop source. Do not write parent variables from inside the Block; raise an event and let the screen decide.
Avoid aggregates in OnRender and avoid server calls in OnInitialize for data that depends on a user choice. OnInitialize is for static defaults; OnReady is for the first data load; user-driven changes belong in the change handler.
Test the loop cases: rapid country switching, selecting the same country twice, clearing the country, and a browser refresh with a saved CountryId. The expected call count is one region fetch per real country change, not one per render.