Skip to content

React Native

BlaC’s core and React bindings are platform-agnostic JavaScript — @blac/core and @blac/react install and run in React Native without modification. The one feature that needs a platform adapter is persistence: the built-in persist plugin uses IndexedDB, which does not exist in React Native. This page covers both topics.

Terminal window
# npm / yarn / bun
npm install @blac/core @blac/react

useBloc, watch, Cubit, and every other core API work the same in React Native as in the browser — write blocs and call useBloc exactly as in React getting started; only <View>/<Text> replace HTML elements in the JSX. No polyfills are needed for the core reactive machinery.

The official persist plugin ships one built-in adapter, NativeIndexedDbAdapter, which needs the global indexedDB — an API that does not exist in React Native. Supply a custom adapter (see Persistence: custom storage adapter for the IndexedDbPersistAdapter interface) that wraps AsyncStorage instead:

import type {
IndexedDbPersistAdapter,
PersistedRecord,
} from '@blac/plugin-persist';
// AsyncStorage type stub — the real type comes from
// @react-native-async-storage/async-storage
interface AsyncStorageLike {
getItem(key: string): Promise<string | null>;
setItem(key: string, value: string): Promise<void>;
removeItem(key: string): Promise<void>;
getAllKeys(): Promise<readonly string[]>;
multiRemove(keys: string[]): Promise<void>;
}
export function createAsyncStorageAdapter(
storage: AsyncStorageLike,
namespace = 'blac:',
): IndexedDbPersistAdapter {
const prefixed = (key: string) => `${namespace}${key}`;
return {
isAvailable: () => true, // AsyncStorage is always available in RN.
async get<T>(key: string): Promise<PersistedRecord<T> | null> {
const raw = await storage.getItem(prefixed(key));
if (raw === null) return null;
try {
return JSON.parse(raw) as PersistedRecord<T>;
} catch {
return null;
}
},
async put<T>(record: PersistedRecord<T>): Promise<void> {
await storage.setItem(prefixed(record.id), JSON.stringify(record));
},
async delete(key: string): Promise<void> {
await storage.removeItem(prefixed(key));
},
async clear(): Promise<void> {
const all = await storage.getAllKeys();
const ours = (all as string[]).filter((k) => k.startsWith(namespace));
if (ours.length > 0) await storage.multiRemove(ours);
},
};
}

Wire it up once at startup, same as any adapter:

import { createIndexedDbPersistPlugin } from '@blac/plugin-persist';
import { getPluginManager } from '@blac/core';
// import AsyncStorage from '@react-native-async-storage/async-storage';
const persist = createIndexedDbPersistPlugin({
adapter: createAsyncStorageAdapter(AsyncStorage),
});
persist.persist(UserSettingsCubit);
getPluginManager().install(persist);

Everything else — registration options, hydration status, serialization constraints — is identical to the browser plugin. See Persistence Plugin for the rest.

  • Persistence Plugin — full plugin API, registration options, status monitoring, and $blac.hydration.wait()
  • Instance Managementacquire, release, and the registry lifecycle
  • watch — observing blocs outside React (useful for imperative React Native patterns)
  • Passing Inputsargs and instance identity