Skip to Content
GuidesProgressive Rendering with React

Progressive Rendering with React

jsoncurrent gives you three rendering strategies you can mix per-field:

Stream everything — render from data on every change event. Fields populate as they arrive. Simple, works for most cases.

Wait for completion — render from onPathComplete. Only show a field once it’s fully assembled. Good for fields where partial values look broken.

Skeleton → complete — show a skeleton on pathstart, replace with real content on pathcomplete. The best UX for complex nested values like cards or sections.

Stream everything

function Report() { const { data, status } = useJsonCurrent<Report>({ /* wire transport */ }) return ( <div> <h1>{data.title}</h1> {data.sections?.map((s, i) => ( <section key={i}> <h2>{s.heading}</h2> <p>{s.body}</p> </section> ))} {status === 'streaming' && <Spinner />} </div> ) }

Skeleton → complete

function Report() { const [sections, setSections] = useState<RenderedSection[]>([]) const { data, status, consume, complete, reset } = useJsonCurrent<Report>({ onPathStart: (path) => { if (/^sections\[\d+\]$/.test(path)) { setSections(prev => [...prev, { id: path, ready: false, value: null }]) } }, onPathComplete: (path, value) => { if (/^sections\[\d+\]$/.test(path)) { setSections(prev => prev.map(s => s.id === path ? { ...s, ready: true, value } : s) ) } }, }) return ( <div> <h1>{data.title}</h1> {sections.map(s => s.ready ? <SectionCard key={s.id} {...s.value} /> : <SectionSkeleton key={s.id} /> )} </div> ) }

Wait for a specific field

Use onPathComplete with an exact path match to only render once a field is sealed:

const [description, setDescription] = useState<string>('') useJsonCurrent<Report>({ onPathComplete: (path, value) => { if (path === 'description') setDescription(value as string) }, })

onChange vs data

data updates on every patch and triggers a re-render. onChange gives you the same state without necessarily triggering a React re-render — useful for syncing to an external store or writing to a ref:

const latestRef = useRef<Partial<Report>>({}) useJsonCurrent<Report>({ onChange: (state) => { latestRef.current = state }, })
Last updated on