Use useBitfieldData(...) when a React component needs data that Runtime Kit has already prepared for that surface.
What this is
useBitfieldData(...) is the public React read hook. It gives a component one consistent return shape:{
data: T | null;
loading: boolean;
error: Error | null;
}
That shape is the point. Your component can render data, loading, and error states without importing the code that prepared the data.The mental model
The component asks for data by using the hook. Runtime Kit decides what data name that component is allowed to read. The component receives the latest app-facing value.This is not a normal fetch call. The component is not asking a server for a record by URL. It is reading a prepared app value. Runtime Kit may prepare that value from local data, package records, package-owned bytes, derived values, or another public package surface. The component should not import that preparation path.How it works technically
package material becomes app-facing data
-> Runtime Kit exposes a read input to this component tree
-> useBitfieldData(...) selects the default input or a named input
-> React receives { data, loading, error }
The public hook call is stable even when Runtime Kit changes how it prepares the value.For the exact selector forms, return-state contract, and invalid examples, read Runtime Kit API.| Public concept | Meaning |
|---|
| Named data | Data Runtime Kit has already made available to the app surface. |
| Selector | A public way to pick which data name you want. |
data | The current materialized value, or null if none is ready. |
loading | true while Runtime Kit is preparing or waiting for the value. |
error | An Error when the read surface cannot provide the value. |
Import
import { useBitfieldData } from '@bitfield/runtime-kit/react';
Do not import from unpublished Runtime Kit paths. The public React package exports the hook.Use the hook without an argument when the surface has one default prepared value.import { useBitfieldData } from '@bitfield/runtime-kit/react';
type WelcomeData = {
headline: string;
body: string;
};
export function WelcomePanel() {
const welcome = useBitfieldData<WelcomeData>();
if (welcome.loading) return <section>Loading</section>;
if (welcome.error) return <section>Could not load this panel.</section>;
if (!welcome.data) return null;
return (
<section>
<h2>{welcome.data.headline}</h2>
<p>{welcome.data.body}</p>
</section>
);
}
Use a string selector when the surface exposes more than one data name.const welcome = useBitfieldData<WelcomeData>('welcome');
const profile = useBitfieldData<{ name: string }>('profile');
The string is not a storage path. It is a public input name made available to this surface.Read with local params
Some surfaces may allow a selection object with params. Params are local selection data, like the current search query or selected item id.const result = useBitfieldData<SearchResult>({
input: 'search-results',
params: { query },
});
Use params for the user selection on this screen. Do not use params to smuggle private storage or setup into a component.Render every state
Good Runtime Kit components handle four states.if (store.loading) return <section>Loading</section>;
if (store.error) return <section>{store.error.message}</section>;
if (!store.data) return <section>No data yet</section>;
return <section>{store.data.title}</section>;
That sounds simple because it should be simple. Runtime Kit owns the preparation work.Pair it with a request
Use the hook for reading. Use sendRequestToBitfieldTarget(...) when the user asks something to do work.import { sendRequestToBitfieldTarget } from '@bitfield/runtime-kit';
import { useBitfieldData } from '@bitfield/runtime-kit/react';
export function SearchBox() {
const results = useBitfieldData<SearchResult[]>('search-results');
async function runSearch(query: string) {
await sendRequestToBitfieldTarget({
target: 'product.search',
payload: { query },
});
}
return (
<section>
<button type="button" onClick={() => runSearch('blue jacket')}>
Search
</button>
{results.data?.map((item) => <p key={item.id}>{item.name}</p>)}
</section>
);
}
The request asks a target to do work. The hook reads prepared results.Before / after
| Before | After |
|---|
| Component imports storage helpers. | Component imports one hook. |
| Component chooses low-level data wiring. | Runtime Kit handles preparation behind the surface. |
| Component imports package implementation details. | Component uses public input names and data shape. |
| The component has many low-level APIs to misuse. | The component gets one read shape and fewer ways to tangle the app. |
Common mistakes
Using the hook as setup codeDo not make the component create package state, storage addresses, or low-level wiring. The component reads prepared app data.Skipping loading and empty statesdata can be null. Treat that as a real state, not an error.Assuming every selector is globalA selector is scoped to the surface that Runtime Kit prepared. If a selector is not available, fix the package/surface boundary instead of hardcoding private reads in the component.Deep importing unpublished Runtime Kit codeOnly import from @bitfield/runtime-kit/react. If code needs private setup machinery, that code is not app component code.Quick reference
const store = useBitfieldData<MyData>();
const named = useBitfieldData<MyData>('input-name');
const selected = useBitfieldData<MyData>({
input: 'input-name',
params: { id },
});
Return shape:{
data: T | null;
loading: boolean;
error: Error | null;
}
Now build the bigger version
Build a real screen with two data names and one request.import { sendRequestToBitfieldTarget } from '@bitfield/runtime-kit';
import { useBitfieldData } from '@bitfield/runtime-kit/react';
type WelcomeCopy = { headline: string; body: string };
type Checklist = { items: string[] };
export function LaunchPanel() {
const welcome = useBitfieldData<WelcomeCopy>('welcome-copy');
const checklist = useBitfieldData<Checklist>('launch-checklist');
async function getNextStep() {
await sendRequestToBitfieldTarget({
target: 'launch.next-step',
payload: { completed: checklist.data?.items.length ?? 0 },
});
}
if (welcome.loading || checklist.loading) return <section>Loading launch plan.</section>;
if (welcome.error || checklist.error) return <section>Could not load launch plan.</section>;
if (!welcome.data || !checklist.data) return <section>No launch plan yet.</section>;
return (
<section>
<h2>{welcome.data.headline}</h2>
<p>{welcome.data.body}</p>
{checklist.data.items.map((item) => <p key={item}>{item}</p>)}
<button type="button" onClick={getNextStep}>Get next step</button>
</section>
);
}
The component is doing real work, but it still only uses data names, an action name, and public payload shapes.