Skip to main content

When a user does something — connects a service, completes a task, sends a message — the screen should reflect it instantly, with no refresh button, no reopening the screen, and no hand-written copy of the new state. This page shows the one loop that makes that happen.

The product moment

A user clicks Connect on a service tile. The credential is saved. The tile should flip to Connected the moment the save lands — on its own.The wrong way to get there is to fake it: flip the tile in component state because you “know” the connect succeeded, or re-pull the whole feed every time the screen mounts. Both drift from the real data, and both are extra code you later have to delete. The right way is a single reactive loop where the rendered screen is always a direct projection of the saved data.

The loop

act

A surface asks a target to do work with sendRequestToBitfieldTarget(…).

change

The target writes the package records the prepared value is built from.

rebuild

A change-driven rule re-prepares the named value from the new records.

render

useBitfieldData(…) receives the new value and React re-renders.

Every arrow is automatic once the rule exists. The component does not poll, does not re-fetch on mount, and never holds a second copy of the truth.

The read side is already live

useBitfieldData(...) is not a one-time fetch. It is a live subscription to a named value. When that value changes, every component reading it re-renders with the new value.
You never call a “refresh” function here. If the named value changes, this list updates by itself. So the real question is not “how do I refresh the component?” It is “what makes the named value change?”

The write side changes the records

A user action asks a target to do work. That target writes the package records the named value is prepared from.
This is the part that matters most: the write must change the same records the prepared value is built from. If your screen shows a value derived from records A, B, and C, then a connect that only writes record D will never change the screen — no matter how reactive the rest of the loop is. The write and the projection must agree on which records carry the truth.Between “records changed” and “named value changed” sits the piece people forget. The prepared value does not rebuild itself just because some record changed somewhere. A package declares a reactive rule that watches the records the value depends on and re-prepares the value when any of them change.State the rule with three facts:Declare this once, as package data. After that the loop is closed: a write changes a watched record, the rule fires, the named value is rebuilt, and every subscribed component re-renders. No surface code runs the rebuild, so no surface can forget to.The rule lives next to the package data, not in the component. That separation is the whole point — the screen stays a dumb projection, and the reactive behavior is owned by the package that owns the data.

Make the rule and the projection match

The most common reason a correct-looking loop still shows stale state: the reactive rule watches one set of records, but the prepared value is built from a different set. The write updates records the rule does not watch, or the rule rebuilds from records the write does not touch. Keep one answer to “which records carry this truth,” and point both the rule and the projection at it.

Anti-patterns

These three shortcuts all look like they work and all fight the loop. Delete them.Optimistic local copy. The component keeps its own connectedIds set and flips a row to connected because the request resolved. Now there are two truths — the local set and the prepared value — and they drift the first time a write partly fails or another surface changes the same data. Let the write change the records and let the rule rebuild the value. The render is the truth.Re-pull on mount. The surface rebuilds the whole feed in a mount effect “so it is fresh when the screen opens.” This hides a missing reactive rule: it makes opening the screen the refresh, instead of the data change being the refresh. It also does nothing while the screen is already open. Remove the mount effect and add the rule.Manual rebuild after every write. Each action calls the rebuild itself right after writing. This works until one new caller forgets, and it couples every writer to the projection. One reactive rule replaces every one of these calls and can never be forgotten.

What this prevents

Verify

What should happen

Next

Read Read data in React for the read hook contract and selectors.Read Send a request for payloads, replies, and request errors on the write side.Read React surface for package data for a full read-plus-request surface to attach this loop to.Read Package to screen for the full path from package data to a rendered surface.Read Runtime Kit API for the exact useBitfieldData(...) and sendRequestToBitfieldTarget(...) contracts.
Last modified on June 30, 2026