Journal

· guides

Virtualizing live chat without losing the conversation

A windowed chat history works only when newest-edge anchoring, stable row identity, and the reader's place survive the migration.

A narrow message window crosses a longer conversation trace, with a verdigris pin marking the newest edge.

The bottom of a live conversation is application state. Our Muniment Mobile implementation moved from an eager scroll container to a windowed list. It preserves when the screen follows the newest turn and when it leaves a reader alone. Mounting fewer rows was only the rendering change. The interaction contract was the work.

Offset zero carries meaning

Our mobile thread orders its data newest first and renders it through an inverted list. The newest turn therefore sits at offset zero on entry while the conversation still reads chronologically on screen. React Native documents inversion, initial rendering, stable key extraction, and offscreen windowing as separate concerns of FlatList. Combining them does not define chat behavior for the application.

Muniment Mobile treats an offset within a small threshold of zero as pinned to the newest edge. When a streamed reply changes the content size, the list follows only if that pin remains active. A reader who has moved into older messages keeps that position as new content arrives. Sending a message makes a deliberate choice in the other direction. The screen restores the pinned state and scrolls to offset zero.

This is the useful boundary. A coordinate reports where the viewport is. Pinned state records whether the user has chosen to follow the conversation.

Rows need identities that survive streaming

Our mobile implementation puts stored messages, optimistic local sends, and in-progress streamed replies into one conversation-row model. Each row key derives from its stored or local status and message identity. Later chunks can update the active reply without giving unrelated rows new identities.

The FlatList reference says its extracted key is used for caching and for tracking reordering. That framework rule matters here, but it is not the design. The design is choosing identities that remain true while a local turn becomes complete and a streaming turn grows.

Three interaction rules carried the migration:

  • Enter at the newest turn.
  • Follow streamed size changes only while the newest-edge pin is active.
  • Re-pin after the user sends a message.

Those rules, along with stable stored, local, and streaming row identities, describe our implemented mobile behavior.

The fixture proves a window, then tests the anchor

Our regression fixture contains 220 synthetic messages. It checks the initial and advanced render windows explicitly.

Check Message 219 Message 100 Message 0
Initial mount mounted not mounted not mounted
Render window advanced into history newest-edge entry established available outside this assertion

That fixture catches an eager history masquerading as a windowed one. It also proves that an older row becomes available when the simulated window reaches it. Our interaction coverage checks pinned versus scrolled-back streaming. It then checks that sending re-pins and returns the list to the newest turn. Our streaming coverage also verifies that later chunks do not needlessly re-render stored messages, optimistic user rows, or completed local replies.

These checks establish rendering and interaction correctness. They do not measure latency, frame rate, memory use, or a quantified device-performance gain. React Native’s optimization guide describes a general tradeoff between render-window size, blank areas, memory, and responsiveness; it reports no measurement of Muniment Mobile.

A long conversation can now expose only the rows its window needs without turning every incoming chunk into a command to abandon the past. That restraint is part of the chat, too.

Sources

  1. React Native — FlatList reactnative.dev
  2. React Native — Optimizing FlatList Configuration reactnative.dev

Continue reading

All publications

Early access

One governed workspace for every model

See which work produced each model bill, with grants, routing, and records in one place.