Schnellstart
Installation
npm install @violetflux/kerros pnpm add @violetflux/kerros yarn add @violetflux/kerros bun add @violetflux/kerros
Kerros funktioniert mit npm, pnpm, Yarn und Bun und unterstützt React 17, 18 und 19.
Einen Store erstellen
Jeder custom Hook kann mit createStore zu einem zwischen Komponenten geteilten Store werden.
import { createStore } from '@violetflux/kerros'
import { useState } from 'react'
interface Task {
id : string
title : string
}
function useTaskStoreValue () {
const [ tasks , setTasks ] = useState < Task []>([])
const addTask = (task : Task ) => {
setTasks (v => [ ... v , task])
}
const finishTask = (taskId : string ) => {
setTasks (v => v .filter (task => task .id !== taskId))
}
return { tasks , addTask , finishTask }
}
export const [ useTask , TaskProvider ] = createStore (useTaskStoreValue)
createStore gibt den Hook für Komponenten und den dazugehörigen Provider zurück. Im Store kannst du weiterhin useState, useReducer, Context, SDK Hooks und eigene Hooks verwenden.
Verwende für den Initializer einen benannten Top-Level-Hook wie useTaskStoreValue. Anonyme Initializer funktionieren weiterhin, werden vom React Compiler im infer-Modus aber nicht automatisch als Hooks kompiliert.
Provider einbinden
useTask darf nur unterhalb von TaskProvider aufgerufen werden.
function App () {
return (
< TaskProvider >
< Header />
< TaskList />
</ TaskProvider >
)
}
Außerhalb des Providers wirft Kerros einen verständlichen Fehler.
Store in einer Komponente verwenden
Der Selektor gibt nur die Felder zurück, welche die Komponente tatsächlich nutzt.
function TaskList () {
const { tasks , finishTask } = useTask (s => ({
tasks : s .tasks ,
finishTask : s .finishTask ,
}))
return (
< ul >
{ tasks .map (task => (
< li key = { task .id}>
{ task .title}
< button onClick = {() => finishTask ( task .id)}>Erledigt</ button >
</ li >
))}
</ ul >
)
}
Kerros vergleicht die obersten Felder des Selektor-Objekts flach. Solange diese ausgewählten Felder gleich bleiben, rendern andere Store-Updates TaskList nicht neu. Der Selektor darf inline stehen und braucht kein useCallback.
Mehrere Store-Instanzen
Jeder eingebundene Provider erstellt einen unabhängigen Store.
< TaskProvider >
< h2 >Private Aufgaben</ h2 >
< TaskList />
</ TaskProvider >
< TaskProvider >
< h2 >Teamaufgaben</ h2 >
< TaskList />
</ TaskProvider >
Jede TaskList liest automatisch den nächstgelegenen Provider. Die Daten bleiben getrennt.
Abhängigkeiten zwischen Stores
Ein Store kann einen anderen Store direkt aufrufen.
function useTaskStoreValue () {
const { user } = useAccount (s => ({ user : s .user }))
const [ tasks , setTasks ] = useState < Task []>([])
const addTask = (title : string ) => {
if ( ! user)
return
setTasks (v => [ ... v , {
id : crypto .randomUUID () ,
title ,
assigneeId : user .id ,
}])
}
return { tasks , addTask }
}
export const [ useTask , TaskProvider ] = createStore (useTaskStoreValue)
Der Provider der Abhängigkeit liegt außen. Halte die Abhängigkeit einseitig.
< AccountProvider >
< TaskProvider >
< App />
</ TaskProvider >
</ AccountProvider >
Props an den Provider übergeben
Provider props werden an den Store Hook weitergegeben.
function useCounterStoreValue ({ initialCount } : { initialCount : number }) {
const [ count , setCount ] = useState (initialCount)
return { count , setCount }
}
const [ useCounter , CounterProvider ] = createStore (useCounterStoreValue)
< CounterProvider initialCount = { 42 }>
< Counter />
</ CounterProvider >
Ausprobieren
Dieser Zähler verwendet dieselbe API aus createStore + Provider + selector.
Count: 0
Weiter geht es mit Selektoren und Store-Komposition .