Release candidate — 1.0.0-rc.7
StitchAPI

React Native

A streaming XHR adapter (the streaming fetch bare RN lacks), an AsyncStorage-backed StitchStore for persistent sessions, and AppState/NetInfo refetch helpers — plus the re-exported useStitch / useStitchStream hooks.

Use @stitchapi/react-native when you call stitches from a bare React Native app. The useStitch / useStitchStream hooks are re-exported verbatim from @stitchapi/react — they are pure useSyncExternalStore over the shared @stitchapi/query-core store and run unchanged on React Native. What this package adds is the platform glue bare RN needs.

On Expo, use @stitchapi/expo instead — expo/fetch streams natively, so it needs none of the XHR shim or polyfills below.

Why a dedicated adapter

StitchAPI is streaming-first, but bare RN's global fetch cannot stream: response.body is undefined, not a ReadableStream (facebook/react-native#27741). RN's XMLHttpRequest, however, exposes responseText incrementally as bytes arrive. rnStreamAdapter wraps that growing text in a real ReadableStream, which is exactly what core's sse / stream decoders consume — while non-streaming requests delegate to core's buffered xhrAdapter. The adapter field it plugs into is the same transport seam every stitch has, so nothing above it changes.

Example

Install the bindings, the shared store, core, and React Native:

npm install @stitchapi/react-native@rc @stitchapi/react@rc @stitchapi/query-core@rc stitchapi@rc

stitchapi, react, and react-native are peer dependencies; @react-native-async-storage/async-storage and @react-native-community/netinfo are optional peers, for the store and reconnect helpers.

Polyfills (streaming only)

Hermes ships no TextEncoder / TextDecoder / ReadableStream, which the stream decoder needs. Install them once at your app's entry — rnStreamAdapter throws a precise error if they're missing. Non-streaming stitches need none of this.

import 'react-native-polyfill-globals/auto';

Wire it into a seam

rnStreamAdapter streams when asked and buffers otherwise; asyncStorageStore makes the auth vault and throttle counters survive app restarts:

import AsyncStorage from '@react-native-async-storage/async-storage';
import { asyncStorageStore, rnStreamAdapter } from '@stitchapi/react-native';
import { seam } from 'stitchapi';

export const api = seam({
    baseUrl: 'https://api.example.com',
    adapter: rnStreamAdapter(),
    store: asyncStorageStore(AsyncStorage),
});

Stream deltas into a component

import { rnStreamAdapter, useStitchStream } from '@stitchapi/react-native';
import { sse } from 'stitchapi/sse';

const chat = sse({
    url: 'https://api.example.com/chat',
    adapter: rnStreamAdapter(),
});

function Chat({ prompt }: { prompt: string }) {
    const { chunks, isStreaming } = useStitchStream(chat, { body: { prompt } });
    return (
        <Text>
            {(chunks as string[]).join('')}
            {isStreaming ? '▌' : null}
        </Text>
    );
}

Refetch on foreground / reconnect

The data lifecycle a mobile app expects — refetch when the app returns to the foreground, and when connectivity comes back:

import NetInfo from '@react-native-community/netinfo';
import {
    useAppActiveRefetch,
    useReconnectRefetch,
    useStitch,
} from '@stitchapi/react-native';

function Inbox() {
    const q = useStitch(getInbox, {});
    useAppActiveRefetch(q);
    useReconnectRefetch(q, { netInfo: NetInfo });
    // ...
}

useAppActiveRefetch uses RN's built-in AppState (no extra dependency); useReconnectRefetch takes your NetInfo module. Both are also available as plain functions — onAppActive(appState, cb) and onReconnect(netInfo, cb) — for use outside React.

The persistent store

asyncStorageStore(storage, options?) accepts any client matching { getItem, setItem, removeItem }. Values ride in a JSON envelope with an absolute expiry (AsyncStorage has no native TTL), and increment is serialized so concurrent increments stay atomic — the throttle counter behaves exactly as it does on Redis. It is proven against the same verifyStoreContract kit every StitchStore passes.

See also

On this page