React Native Runtimes
Guides

Performance tips

Practical advice for getting the most out of threaded runtimes and shared state.

Prewarm what the user will see next

Prewarming a runtime is cheap if it's already warm and one-time-expensive if it isn't. The best time to start a runtime is while the user is doing something else — reading a list, scrolling an inbox, scrubbing onboarding.

useEffect(() => {
  for (const runtimeName of visibleConversationRuntimes) {
    void ThreadedRuntime.prewarm(runtimeName);
  }
}, [visibleConversationRuntimes]);

For app-lifetime runtimes (background, sync engines), prewarm from native startup so the runtime exists before any JS asks for it.

Keep props small

Every prop change crosses the threaded boundary as JSON. Pass ids, cursors, and config values — not full datasets. Use shared state for anything large or mutable.

Prefer update over set for derived writes

When a write depends on the current value, use update. It reads your local value and writes it back. Like plain set(), it races if another runtime writes between the read and write, but it's still preferred over read-then-set for the same local copy. Design your app to have one writer per path instead of relying on atomicity.

await messages.update(current => [...(current ?? []), newMessage]);

Pre-declare hot paths

For state that the app touches early, list it in createSharedStore({ subtrees: [...] }) so it hydrates on store creation — no first-touch latency.

Avoid runtime-per-mount

Pick runtime names by logical owner (conversation id, feed type, business unit), not by component instance. Reusing the runtime across mounts means the JS heap, cached requires, and registered loaders all stay warm.

Tear down what you don't need

Long-running runtimes hold JS heap. For runtimes that own a single transient screen, use destroyOnUnmount on ThreadedScreen so they release when the user leaves.

<ThreadedScreen
  component={ConversationScreen}
  destroyOnUnmount
  props={{ conversationId }}
  runtimeName={`conversation-${conversationId}-runtime`}
/>

App-lifetime runtimes (background, sync) should not be destroyed.

Measure both sides

When evaluating "does threading help", compare:

  • The main-runtime baseline (LegendList on main).
  • The threaded version (LegendList on its own runtime).

The sample app has both screens for exactly this purpose.

On this page

React Native Runtimes is built with by Margelo

We build fast and beautiful apps. Contact us at margelo.com for high-end consultancy services.

Let's talk