Démarrage rapide
Installation
npm install @violetflux/kerros pnpm add @violetflux/kerros yarn add @violetflux/kerros bun add @violetflux/kerros
Kerros fonctionne avec npm, pnpm, Yarn et Bun, et prend en charge React 17, 18 et 19.
Créer un Store
N'importe quel custom Hook peut devenir un état partagé grâce à createStore.
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 renvoie le Hook utilisé par les composants et son Provider. Le Store peut toujours utiliser useState, useReducer, Context, des Hooks SDK ou vos propres Hooks.
Conservez l'initializer sous la forme d'un Hook nommé au niveau du module, comme useTaskStoreValue. Les initializers anonymes continuent de fonctionner, mais React Compiler ne les compile pas automatiquement comme Hooks en mode infer.
Monter le Provider
useTask ne peut être appelé que dans les descendants de TaskProvider.
function App () {
return (
< TaskProvider >
< Header />
< TaskList />
</ TaskProvider >
)
}
En dehors du Provider, Kerros lève une erreur explicite.
Utiliser le Store dans un composant
Le sélecteur renvoie uniquement les champs utilisés par le composant.
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)}>Terminer</ button >
</ li >
))}
</ ul >
)
}
Kerros compare superficiellement les champs de premier niveau de l'objet. Tant que ces champs sélectionnés restent égaux, les autres mises à jour du Store ne rendent pas TaskList à nouveau. Le sélecteur peut rester en ligne et n'a pas besoin de useCallback.
Plusieurs instances
Chaque Provider monté crée un Store indépendant.
< TaskProvider >
< h2 >Tâches personnelles</ h2 >
< TaskList />
</ TaskProvider >
< TaskProvider >
< h2 >Tâches de l'équipe</ h2 >
< TaskList />
</ TaskProvider >
Chaque TaskList lit automatiquement le Provider le plus proche. Les données restent isolées.
Dépendances entre Stores
Un Store peut appeler un autre Store directement.
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)
Montez le Provider de la dépendance à l'extérieur et gardez une dépendance unidirectionnelle.
< AccountProvider >
< TaskProvider >
< App />
</ TaskProvider >
</ AccountProvider >
Passer des props au Provider
Les props du Provider sont transmises au Hook du Store.
function useCounterStoreValue ({ initialCount } : { initialCount : number }) {
const [ count , setCount ] = useState (initialCount)
return { count , setCount }
}
const [ useCounter , CounterProvider ] = createStore (useCounterStoreValue)
< CounterProvider initialCount = { 42 }>
< Counter />
</ CounterProvider >
Essayer
Ce compteur utilise la même API createStore + Provider + selector.
Count: 0
Continuez avec les Sélecteurs et la Composition .