API reference

Kerros has one public function: createStore.

createStore(useStoreValue)

Turn a React Hook into a consumer Hook and Provider:

function useCounterStoreValue() {
  const [count, setCount] = useState(0)
  return { count, setCount }
}

const [useCounter, CounterProvider] = createStore(useCounterStoreValue)

Type signature:

function createStore<TStore, TProps = Record<never, never>>(
  useStoreValue: (props: TProps) => TStore,
): readonly [StoreHook<TStore>, StoreProvider<TProps>]

useStoreValue

useStoreValue is the Store implementation Hook. It may call other React Hooks and return the state and actions that should be shared:

function useThemeStoreValue() {
  const [dark, setDark] = useState(false)
  const toggle = () => setDark(v => !v)

  return { dark, toggle }
}

const [useTheme, ThemeProvider] = createStore(useThemeStoreValue)

It must follow the Rules of Hooks.

Define it as a top-level function named useXxxStoreValue. An anonymous initializer remains valid at runtime, but React Compiler infer mode does not automatically recognize and compile it as a Hook.

Return value

createStore returns two values:

const [useTheme, ThemeProvider] = createStore(useThemeStoreValue)
  • useTheme is the Hook used by components or dependent Stores
  • ThemeProvider is the React component that creates and owns a Store instance

Domain names such as useTheme and ThemeProvider are recommended; repeating Store is optional.

Store Hook

The Store Hook requires an object-returning selector:

const { dark, toggle } = useTheme(s => ({
  dark: s.dark,
  toggle: s.toggle,
}))

Kerros shallowly compares the returned object's top-level fields with Object.is. The component does not rerender for other Store updates while those selected fields stay equal.

Calling the Hook outside its matching Provider throws:

Kerros store hook must be used within its matching Provider

Provider props

All Provider props except children are passed to the Store Hook:

interface CounterProps {
  initialCount: number
}

function useCounterStoreValue({ initialCount }: CounterProps) {
  const [count, setCount] = useState(initialCount)
  return { count, setCount }
}

const [useCounter, CounterProvider] = createStore(useCounterStoreValue)
<CounterProvider initialCount={10}>
  <Counter />
</CounterProvider>

Every mounted Provider creates an independent Store instance.

React versions

ReactSubscription implementation
React 17use-sync-external-store compatibility shim
React 18React's native useSyncExternalStore when available
React 19React's native implementation, compatible with React Compiler

React Compiler is optional.

Server rendering

Kerros supplies getServerSnapshot to useSyncExternalStore. The Provider's initial result is used for the server snapshot, and later values are published only after the Provider commits so consumers never observe an abandoned render.