Subscribe and render the current value
The first value can arrive before a listener is registered. After engine readiness, resolve the intended model, retain the callback identity, subscribe and render the current value once. The owned root-model example demonstrates viewEnv.addDataChangedCallback paired with removal using the same resource ID; injected models need their own verified identity.
The inspected bundled ModelObserver(featureName) scanned existing subviews once at engine readiness. It did not follow a matching carrier added later. Either establish attachment before that scan or own a scoped late-subview subscription and its teardown. Do not let a readiness event and a fallback poll each install the same listeners.
A restored route is not restored navigation data
Current public source; version-sensitive. The client SubstateRouter subscribes its model commands, then connects to the state machine. The machine's connect path immediately reports matching entered states without the original navigation event. The router publishes each matching descendant with empty parameters in that case; it does not recover the earlier event payload or serialize recorded state. An exit alone does not clear the router model.
Supply a late-created panel's required context through its owning view or an explicit current-state snapshot. Keep the route, selected identity and data-readiness state separate so empty initial parameters cannot erase a valid selection. Route re-entry can also reuse the same view; see reused-view context adoption.
The router's finalization removes model commands and disconnects its observer. Framework observer clearing alone does not demonstrate that those model commands were removed: the concrete view or state must own finalization. A route-owned router can need release before the longer-lived window is destroyed. Verify late attachment, route exit, replacement and reopen independently; these Python paths do not establish frontend mounting or native readiness timing.
Choose an update signal
| Need | Signal | Ownership rule |
|---|---|---|
| Python/native model changed | Model data callback | Register/remove callback with the original resource ID. |
| React replaced target DOM | MutationObserver on a stable container | Query the current subtree; do not retain native nodes across replacement. |
| Many changes need one render | Queued requestAnimationFrame | One retained frame handle; cancel and invalidate it on disposal. |
| Missing startup dependency | Readiness event or bounded startup retry | Stop on success, owner loss or deadline; diagnose exhaustion once. |
| Verified proxy lacks a dependable notification | Cheap low-frequency signature comparison | Render only on change; document the compatibility need. |
| Continuous visual motion | Owned animation frame loop | Choose a rate from the actual latency/work budget. |
Observation is not consumption
An observer can need to inspect a payload to decide whether native rendering removed owned controls. A separate update path can compare that payload with the last rendered value. If the observer advances the rendered signature, it can consume a new revision before reconciliation and prevent the actual update. Keep peeking side-effect-free and advance the applied revision only after the render uses it.
Cache expensive snapshots by owner and revision, while keeping model observation, calculation completion and DOM application distinct. A preliminary model can render successfully while its completed calculation never reaches the DOM. Log those boundaries during diagnosis instead of assuming a frozen value means a broken bridge.
A BigWorld.callback can defer/coalesce an expensive payload build away from a navigation transition, but the work still runs synchronously on the game thread when invoked. Clear its ID before execution and cancel it in finalization. Cache or stage repeated calculations; deferral alone does not make them background work.
Reconciliation and cleanup
DOM reconciliation should recognize already-owned nodes and classes, update only what changed and tolerate native subtree replacement. An informational tooltip needs one active-row authority, plus cleanup on leave, blur, rerender and unload. A preview response also needs its request and view-generation identity so an old hover cannot overwrite a newer selection.
Retain exact handlers, observer objects, callback IDs and timer/frame handles. Remove engine and DOM listeners with their original identities; repeated bind() calls do not match. An inspected helper version bound functions independently during subscribe/unsubscribe, so helper cleanup requires source review too. Cancel handles and invalidate queued continuations: a generation guard prevents stale writes but does not remove scheduled work.
Validate first delivery, updates after the first render, late carrier attachment, native rerender, closing while work is pending, and reopening without duplicate listeners. See lifecycle ownership, existing-view injection and layout/input boundaries.
Coalesce current-state updates
Illustrative: call queueState from the verified model observer, and call disposeUpdates from the actual frontend teardown. The feature owns reconcile and its diagnostics. This deliberately keeps the latest state, so it is suitable for a display projection, not for preserving every historical event. Copy any borrowed proxy data before retaining it.
let alive = true;
let frameId = 0;
let hasPending = false;
let pending;
function queueState(value) {
if (!alive) return;
pending = value;
hasPending = true;
if (frameId) return;
frameId = requestAnimationFrame(function () {
frameId = 0;
if (!alive || !hasPending) return;
const current = pending;
hasPending = false;
pending = undefined;
reconcile(current); // Feature-owned renderer, not a client API.
});
}
function disposeUpdates() {
alive = false;
if (frameId) cancelAnimationFrame(frameId);
frameId = 0;
hasPending = false;
pending = undefined;
}Typed native bridge actions
Tooltips/popovers and sounds use registered native view events or engine calls, not arbitrary service names. Inspect the actual helper and native handler together. Tooltip placement can combine local element bounds, global view position and pixel/rem conversions; typed proxy payloads need deliberate primitive serialization.
An engine.call promise can reject. Handle it only where the feature has a defined recovery path, and retain useful bounded diagnostics rather than wrapping an entire renderer in an empty catch. A vendor SDK example proves neither registration of that service in WoT nor a mod-facing host API.