@violetflux/kerros 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.de.md +89 -0
- package/README.es.md +89 -0
- package/README.fr.md +89 -0
- package/README.ja.md +90 -0
- package/README.ko.md +90 -0
- package/README.md +204 -18
- package/README.zh-CN.md +218 -0
- package/package.json +4 -1
package/README.de.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://violetflux.github.io/kerros/de/"><img src="https://raw.githubusercontent.com/violetflux/kerros/main/docs/public/banner.svg" alt="Kerros" width="100%" /></a>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.md">English</a> ·
|
|
7
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.zh-CN.md">简体中文</a> ·
|
|
8
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.ja.md">日本語</a> ·
|
|
9
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.ko.md">한국어</a> ·
|
|
10
|
+
Deutsch ·
|
|
11
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.fr.md">Français</a> ·
|
|
12
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.es.md">Español</a>
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
Kerros lässt React-State dort, wo er natürlich hingehört: in Hooks und unter Providern. Die Bibliothek ergänzt gezielte Selector-Abonnements, ohne Reducer, Actions, Proxies oder globale Singletons vorzuschreiben.
|
|
16
|
+
|
|
17
|
+
- Ein Store ist ein normaler React Hook
|
|
18
|
+
- Selektoren geben ein Objekt mit den benötigten Werten zurück
|
|
19
|
+
- Oberste Felder werden flach mit `Object.is` verglichen
|
|
20
|
+
- Jeder Provider besitzt eine isolierte Store-Instanz
|
|
21
|
+
- Stores lassen sich über einseitige Abhängigkeiten komponieren
|
|
22
|
+
- Unterstützt React 17, 18 und 19
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
| Paketmanager | Befehl |
|
|
27
|
+
| --- | --- |
|
|
28
|
+
| npm | `npm install @violetflux/kerros` |
|
|
29
|
+
| pnpm | `pnpm add @violetflux/kerros` |
|
|
30
|
+
| Yarn | `yarn add @violetflux/kerros` |
|
|
31
|
+
| Bun | `bun add @violetflux/kerros` |
|
|
32
|
+
|
|
33
|
+
## Store erstellen
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import { createStore } from '@violetflux/kerros'
|
|
37
|
+
import { useState } from 'react'
|
|
38
|
+
|
|
39
|
+
export const [useCounter, CounterProvider] = createStore(() => {
|
|
40
|
+
const [count, setCount] = useState(0)
|
|
41
|
+
return { count, setCount }
|
|
42
|
+
})
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Im Store Hook können weiterhin `useState`, `useReducer`, Context, SDK Hooks und eigene Hooks verwendet werden.
|
|
46
|
+
|
|
47
|
+
## Provider einbinden und Werte auswählen
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
function Counter() {
|
|
51
|
+
const { count, setCount } = useCounter(s => ({
|
|
52
|
+
count: s.count,
|
|
53
|
+
setCount: s.setCount,
|
|
54
|
+
}))
|
|
55
|
+
return <button onClick={() => setCount(count + 1)}>{count}</button>
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function App() {
|
|
59
|
+
return <CounterProvider><Counter /></CounterProvider>
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Der Selektor darf inline stehen. Änderungen an nicht ausgewählten Feldern rendern `Counter` nicht neu.
|
|
64
|
+
|
|
65
|
+
## Funktionsweise
|
|
66
|
+
|
|
67
|
+
Der Provider führt den Store Hook aus und gibt über Context nur einen stabilen Abonnement-Container weiter. Bestätigte Snapshots werden mit `subscribe/getSnapshot` veröffentlicht. Eine Komponente rendert nur neu, wenn sich ihre Auswahl ändert.
|
|
68
|
+
|
|
69
|
+
Ohne verstecktes Modul-Singleton kann derselbe Provider mehrfach eingebunden, über Props initialisiert, in Tests isoliert oder auf einen Teilbaum begrenzt werden.
|
|
70
|
+
|
|
71
|
+
## API
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
function createStore<TStore, TProps = Record<never, never>>(
|
|
75
|
+
useStoreValue: (props: TProps) => TStore,
|
|
76
|
+
): readonly [StoreHook<TStore>, StoreProvider<TProps>]
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Der zurückgegebene Store Hook verlangt einen Selektor, der ein Objekt liefert. Außerhalb des passenden Providers wird ein verständlicher Fehler ausgelöst. Strict Mode und Server Rendering werden unterstützt.
|
|
80
|
+
|
|
81
|
+
## Dokumentation
|
|
82
|
+
|
|
83
|
+
- [Einführung](https://violetflux.github.io/kerros/de/guide/introduction)
|
|
84
|
+
- [Erste Schritte](https://violetflux.github.io/kerros/de/guide/getting-started)
|
|
85
|
+
- [Selektoren](https://violetflux.github.io/kerros/de/guide/selectors)
|
|
86
|
+
- [Store-Komposition](https://violetflux.github.io/kerros/de/guide/composition)
|
|
87
|
+
- [API](https://violetflux.github.io/kerros/de/api/)
|
|
88
|
+
|
|
89
|
+
[MIT License](https://github.com/violetflux/kerros/blob/main/LICENSE)
|
package/README.es.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://violetflux.github.io/kerros/es/"><img src="https://raw.githubusercontent.com/violetflux/kerros/main/docs/public/banner.svg" alt="Kerros" width="100%" /></a>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.md">English</a> ·
|
|
7
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.zh-CN.md">简体中文</a> ·
|
|
8
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.ja.md">日本語</a> ·
|
|
9
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.ko.md">한국어</a> ·
|
|
10
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.de.md">Deutsch</a> ·
|
|
11
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.fr.md">Français</a> ·
|
|
12
|
+
Español
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
Kerros mantiene el estado de React donde pertenece de forma natural: dentro de Hooks y bajo Providers. Añade suscripciones precisas mediante selectores sin imponer reducers, actions, proxies ni un singleton global.
|
|
16
|
+
|
|
17
|
+
- Un Store es un Hook de React normal
|
|
18
|
+
- Los selectores devuelven un objeto con los valores necesarios
|
|
19
|
+
- Los campos superiores se comparan superficialmente con `Object.is`
|
|
20
|
+
- Cada Provider posee una instancia de Store aislada
|
|
21
|
+
- Los Stores se componen mediante dependencias unidireccionales
|
|
22
|
+
- Compatible con React 17, 18 y 19
|
|
23
|
+
|
|
24
|
+
## Instalación
|
|
25
|
+
|
|
26
|
+
| Gestor | Comando |
|
|
27
|
+
| --- | --- |
|
|
28
|
+
| npm | `npm install @violetflux/kerros` |
|
|
29
|
+
| pnpm | `pnpm add @violetflux/kerros` |
|
|
30
|
+
| Yarn | `yarn add @violetflux/kerros` |
|
|
31
|
+
| Bun | `bun add @violetflux/kerros` |
|
|
32
|
+
|
|
33
|
+
## Crear un Store
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import { createStore } from '@violetflux/kerros'
|
|
37
|
+
import { useState } from 'react'
|
|
38
|
+
|
|
39
|
+
export const [useCounter, CounterProvider] = createStore(() => {
|
|
40
|
+
const [count, setCount] = useState(0)
|
|
41
|
+
return { count, setCount }
|
|
42
|
+
})
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
El Hook del Store puede seguir usando `useState`, `useReducer`, Context, Hooks de SDK y Hooks personalizados.
|
|
46
|
+
|
|
47
|
+
## Montar el Provider y seleccionar valores
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
function Counter() {
|
|
51
|
+
const { count, setCount } = useCounter(s => ({
|
|
52
|
+
count: s.count,
|
|
53
|
+
setCount: s.setCount,
|
|
54
|
+
}))
|
|
55
|
+
return <button onClick={() => setCount(count + 1)}>{count}</button>
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function App() {
|
|
59
|
+
return <CounterProvider><Counter /></CounterProvider>
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
El selector puede escribirse en línea. Cambiar un campo no seleccionado no vuelve a renderizar `Counter`.
|
|
64
|
+
|
|
65
|
+
## Cómo funciona
|
|
66
|
+
|
|
67
|
+
El Provider ejecuta el Hook del Store y Context solo transporta un contenedor de suscripción estable. Los snapshots confirmados se publican mediante `subscribe/getSnapshot`. Cada componente se renderiza de nuevo únicamente cuando cambia su selección.
|
|
68
|
+
|
|
69
|
+
Sin un singleton de módulo oculto, el mismo Provider puede montarse varias veces, inicializarse con props, aislarse en pruebas o limitarse a un subárbol.
|
|
70
|
+
|
|
71
|
+
## API
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
function createStore<TStore, TProps = Record<never, never>>(
|
|
75
|
+
useStoreValue: (props: TProps) => TStore,
|
|
76
|
+
): readonly [StoreHook<TStore>, StoreProvider<TProps>]
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
El Hook devuelto requiere un selector que retorne un objeto. Usarlo fuera de su Provider correspondiente produce un error claro. Admite Strict Mode y renderizado en servidor.
|
|
80
|
+
|
|
81
|
+
## Documentación
|
|
82
|
+
|
|
83
|
+
- [Introducción](https://violetflux.github.io/kerros/es/guide/introduction)
|
|
84
|
+
- [Primeros pasos](https://violetflux.github.io/kerros/es/guide/getting-started)
|
|
85
|
+
- [Selectores](https://violetflux.github.io/kerros/es/guide/selectors)
|
|
86
|
+
- [Composición de Stores](https://violetflux.github.io/kerros/es/guide/composition)
|
|
87
|
+
- [API](https://violetflux.github.io/kerros/es/api/)
|
|
88
|
+
|
|
89
|
+
[Licencia MIT](https://github.com/violetflux/kerros/blob/main/LICENSE)
|
package/README.fr.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://violetflux.github.io/kerros/fr/"><img src="https://raw.githubusercontent.com/violetflux/kerros/main/docs/public/banner.svg" alt="Kerros" width="100%" /></a>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.md">English</a> ·
|
|
7
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.zh-CN.md">简体中文</a> ·
|
|
8
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.ja.md">日本語</a> ·
|
|
9
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.ko.md">한국어</a> ·
|
|
10
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.de.md">Deutsch</a> ·
|
|
11
|
+
Français ·
|
|
12
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.es.md">Español</a>
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
Kerros conserve l'état React là où il se trouve naturellement : dans les Hooks et sous les Providers. Il ajoute des abonnements précis par sélecteur sans imposer reducers, actions, proxies ou singleton global.
|
|
16
|
+
|
|
17
|
+
- Un Store est un Hook React ordinaire
|
|
18
|
+
- Les sélecteurs renvoient un objet contenant les valeurs nécessaires
|
|
19
|
+
- Les champs de premier niveau sont comparés avec `Object.is`
|
|
20
|
+
- Chaque Provider possède une instance de Store isolée
|
|
21
|
+
- Les Stores se composent grâce à des dépendances unidirectionnelles
|
|
22
|
+
- Compatible avec React 17, 18 et 19
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
| Gestionnaire | Commande |
|
|
27
|
+
| --- | --- |
|
|
28
|
+
| npm | `npm install @violetflux/kerros` |
|
|
29
|
+
| pnpm | `pnpm add @violetflux/kerros` |
|
|
30
|
+
| Yarn | `yarn add @violetflux/kerros` |
|
|
31
|
+
| Bun | `bun add @violetflux/kerros` |
|
|
32
|
+
|
|
33
|
+
## Créer un Store
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import { createStore } from '@violetflux/kerros'
|
|
37
|
+
import { useState } from 'react'
|
|
38
|
+
|
|
39
|
+
export const [useCounter, CounterProvider] = createStore(() => {
|
|
40
|
+
const [count, setCount] = useState(0)
|
|
41
|
+
return { count, setCount }
|
|
42
|
+
})
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Le Hook du Store peut continuer à utiliser `useState`, `useReducer`, Context, des Hooks SDK et vos Hooks personnalisés.
|
|
46
|
+
|
|
47
|
+
## Monter le Provider et sélectionner les valeurs
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
function Counter() {
|
|
51
|
+
const { count, setCount } = useCounter(s => ({
|
|
52
|
+
count: s.count,
|
|
53
|
+
setCount: s.setCount,
|
|
54
|
+
}))
|
|
55
|
+
return <button onClick={() => setCount(count + 1)}>{count}</button>
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function App() {
|
|
59
|
+
return <CounterProvider><Counter /></CounterProvider>
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Le sélecteur peut rester en ligne. La modification d'un champ non sélectionné ne provoque pas un nouveau rendu de `Counter`.
|
|
64
|
+
|
|
65
|
+
## Fonctionnement
|
|
66
|
+
|
|
67
|
+
Le Provider exécute le Hook du Store et Context ne transporte qu'un conteneur d'abonnement stable. Les snapshots validés sont publiés via `subscribe/getSnapshot`. Un composant n'est rendu à nouveau que lorsque sa sélection change.
|
|
68
|
+
|
|
69
|
+
Sans singleton de module caché, un même Provider peut être monté plusieurs fois, initialisé par des props, isolé dans les tests ou limité à un sous-arbre.
|
|
70
|
+
|
|
71
|
+
## API
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
function createStore<TStore, TProps = Record<never, never>>(
|
|
75
|
+
useStoreValue: (props: TProps) => TStore,
|
|
76
|
+
): readonly [StoreHook<TStore>, StoreProvider<TProps>]
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Le Hook retourné exige un sélecteur qui renvoie un objet. Son utilisation hors du Provider correspondant lève une erreur claire. Strict Mode et le rendu serveur sont pris en charge.
|
|
80
|
+
|
|
81
|
+
## Documentation
|
|
82
|
+
|
|
83
|
+
- [Introduction](https://violetflux.github.io/kerros/fr/guide/introduction)
|
|
84
|
+
- [Bien démarrer](https://violetflux.github.io/kerros/fr/guide/getting-started)
|
|
85
|
+
- [Sélecteurs](https://violetflux.github.io/kerros/fr/guide/selectors)
|
|
86
|
+
- [Composition des Stores](https://violetflux.github.io/kerros/fr/guide/composition)
|
|
87
|
+
- [API](https://violetflux.github.io/kerros/fr/api/)
|
|
88
|
+
|
|
89
|
+
[Licence MIT](https://github.com/violetflux/kerros/blob/main/LICENSE)
|
package/README.ja.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://violetflux.github.io/kerros/ja/"><img src="https://raw.githubusercontent.com/violetflux/kerros/main/docs/public/banner.svg" alt="Kerros" width="100%" /></a>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.md">English</a> ·
|
|
7
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.zh-CN.md">简体中文</a> ·
|
|
8
|
+
日本語 ·
|
|
9
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.ko.md">한국어</a> ·
|
|
10
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.de.md">Deutsch</a> ·
|
|
11
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.fr.md">Français</a> ·
|
|
12
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.es.md">Español</a>
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
Kerros は React の状態を Hook の中、Provider の下という自然な場所に保ちます。reducer、action、proxy、グローバル singleton を導入せず、selector による限定的な購読を追加します。
|
|
16
|
+
|
|
17
|
+
- Store は通常の React Hook
|
|
18
|
+
- selector は必要な値だけをオブジェクトで返す
|
|
19
|
+
- 選択したトップレベルフィールドを `Object.is` で浅く比較
|
|
20
|
+
- Provider ごとに独立した Store インスタンス
|
|
21
|
+
- 一方向の依存関係で Store を合成可能
|
|
22
|
+
- React 17、18、19 をサポート
|
|
23
|
+
|
|
24
|
+
## インストール
|
|
25
|
+
|
|
26
|
+
| パッケージマネージャー | コマンド |
|
|
27
|
+
| --- | --- |
|
|
28
|
+
| npm | `npm install @violetflux/kerros` |
|
|
29
|
+
| pnpm | `pnpm add @violetflux/kerros` |
|
|
30
|
+
| Yarn | `yarn add @violetflux/kerros` |
|
|
31
|
+
| Bun | `bun add @violetflux/kerros` |
|
|
32
|
+
|
|
33
|
+
## Store を作成する
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import { createStore } from '@violetflux/kerros'
|
|
37
|
+
import { useState } from 'react'
|
|
38
|
+
|
|
39
|
+
export const [useCounter, CounterProvider] = createStore(() => {
|
|
40
|
+
const [count, setCount] = useState(0)
|
|
41
|
+
return { count, setCount }
|
|
42
|
+
})
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Store Hook 内では `useState`、`useReducer`、Context、SDK Hook、カスタム Hook をそのまま利用できます。
|
|
46
|
+
|
|
47
|
+
## Provider を配置して値を選択する
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
function Counter() {
|
|
51
|
+
const { count, setCount } = useCounter(s => ({
|
|
52
|
+
count: s.count,
|
|
53
|
+
setCount: s.setCount,
|
|
54
|
+
}))
|
|
55
|
+
|
|
56
|
+
return <button onClick={() => setCount(count + 1)}>{count}</button>
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function App() {
|
|
60
|
+
return <CounterProvider><Counter /></CounterProvider>
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
selector はインラインで記述できます。選択していないフィールドの変更では `Counter` は再レンダーされません。
|
|
65
|
+
|
|
66
|
+
## 仕組み
|
|
67
|
+
|
|
68
|
+
Provider は Store Hook を実行し、Context には安定した購読コンテナだけを渡します。コミット済みスナップショットは `subscribe/getSnapshot` で公開され、各コンポーネントは選択結果が変わったときだけ再レンダーされます。
|
|
69
|
+
|
|
70
|
+
モジュール内の隠れた singleton がないため、Provider の複数配置、props による初期化、テストでの分離、サブツリー単位のスコープが可能です。
|
|
71
|
+
|
|
72
|
+
## API
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
function createStore<TStore, TProps = Record<never, never>>(
|
|
76
|
+
useStoreValue: (props: TProps) => TStore,
|
|
77
|
+
): readonly [StoreHook<TStore>, StoreProvider<TProps>]
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
返される Store Hook にはオブジェクトを返す selector が必須です。対応する Provider の外で呼び出すと明確なエラーを送出します。Strict Mode とサーバーレンダリングをサポートします。
|
|
81
|
+
|
|
82
|
+
## ドキュメント
|
|
83
|
+
|
|
84
|
+
- [はじめに](https://violetflux.github.io/kerros/ja/guide/introduction)
|
|
85
|
+
- [インストールと基本](https://violetflux.github.io/kerros/ja/guide/getting-started)
|
|
86
|
+
- [Selector](https://violetflux.github.io/kerros/ja/guide/selectors)
|
|
87
|
+
- [Store の合成](https://violetflux.github.io/kerros/ja/guide/composition)
|
|
88
|
+
- [API](https://violetflux.github.io/kerros/ja/api/)
|
|
89
|
+
|
|
90
|
+
[MIT License](https://github.com/violetflux/kerros/blob/main/LICENSE)
|
package/README.ko.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://violetflux.github.io/kerros/ko/"><img src="https://raw.githubusercontent.com/violetflux/kerros/main/docs/public/banner.svg" alt="Kerros" width="100%" /></a>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.md">English</a> ·
|
|
7
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.zh-CN.md">简体中文</a> ·
|
|
8
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.ja.md">日本語</a> ·
|
|
9
|
+
한국어 ·
|
|
10
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.de.md">Deutsch</a> ·
|
|
11
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.fr.md">Français</a> ·
|
|
12
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.es.md">Español</a>
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
Kerros는 React 상태를 Hook 안과 Provider 아래라는 자연스러운 위치에 둡니다. reducer, action, proxy, 전역 singleton을 도입하지 않고 selector 기반의 정밀 구독을 제공합니다.
|
|
16
|
+
|
|
17
|
+
- Store는 평범한 React Hook
|
|
18
|
+
- selector는 필요한 값만 객체로 반환
|
|
19
|
+
- 선택 객체의 최상위 필드를 `Object.is`로 얕게 비교
|
|
20
|
+
- Provider마다 격리된 Store 인스턴스
|
|
21
|
+
- 단방향 의존성을 통한 Store 조합
|
|
22
|
+
- React 17, 18, 19 지원
|
|
23
|
+
|
|
24
|
+
## 설치
|
|
25
|
+
|
|
26
|
+
| 패키지 매니저 | 명령 |
|
|
27
|
+
| --- | --- |
|
|
28
|
+
| npm | `npm install @violetflux/kerros` |
|
|
29
|
+
| pnpm | `pnpm add @violetflux/kerros` |
|
|
30
|
+
| Yarn | `yarn add @violetflux/kerros` |
|
|
31
|
+
| Bun | `bun add @violetflux/kerros` |
|
|
32
|
+
|
|
33
|
+
## Store 만들기
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import { createStore } from '@violetflux/kerros'
|
|
37
|
+
import { useState } from 'react'
|
|
38
|
+
|
|
39
|
+
export const [useCounter, CounterProvider] = createStore(() => {
|
|
40
|
+
const [count, setCount] = useState(0)
|
|
41
|
+
return { count, setCount }
|
|
42
|
+
})
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Store Hook 안에서 `useState`, `useReducer`, Context, SDK Hook, 사용자 Hook을 그대로 사용할 수 있습니다.
|
|
46
|
+
|
|
47
|
+
## Provider를 마운트하고 필요한 값 선택하기
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
function Counter() {
|
|
51
|
+
const { count, setCount } = useCounter(s => ({
|
|
52
|
+
count: s.count,
|
|
53
|
+
setCount: s.setCount,
|
|
54
|
+
}))
|
|
55
|
+
|
|
56
|
+
return <button onClick={() => setCount(count + 1)}>{count}</button>
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function App() {
|
|
60
|
+
return <CounterProvider><Counter /></CounterProvider>
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
selector는 인라인으로 작성할 수 있습니다. 선택하지 않은 필드가 바뀌어도 `Counter`는 다시 렌더링되지 않습니다.
|
|
65
|
+
|
|
66
|
+
## 작동 방식
|
|
67
|
+
|
|
68
|
+
Provider는 Store Hook을 실행하고 Context에는 안정적인 구독 컨테이너만 전달합니다. 커밋된 스냅샷은 `subscribe/getSnapshot`으로 게시되며 컴포넌트는 선택 결과가 바뀔 때만 다시 렌더링됩니다.
|
|
69
|
+
|
|
70
|
+
숨겨진 모듈 singleton이 없으므로 같은 Provider를 여러 번 마운트하고, props로 초기화하고, 테스트에서 격리하거나 특정 하위 트리에만 범위를 지정할 수 있습니다.
|
|
71
|
+
|
|
72
|
+
## API
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
function createStore<TStore, TProps = Record<never, never>>(
|
|
76
|
+
useStoreValue: (props: TProps) => TStore,
|
|
77
|
+
): readonly [StoreHook<TStore>, StoreProvider<TProps>]
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
반환된 Store Hook에는 객체를 반환하는 selector가 필요합니다. 대응하는 Provider 밖에서 호출하면 명확한 오류가 발생합니다. Strict Mode와 서버 렌더링을 지원합니다.
|
|
81
|
+
|
|
82
|
+
## 문서
|
|
83
|
+
|
|
84
|
+
- [소개](https://violetflux.github.io/kerros/ko/guide/introduction)
|
|
85
|
+
- [시작하기](https://violetflux.github.io/kerros/ko/guide/getting-started)
|
|
86
|
+
- [Selector](https://violetflux.github.io/kerros/ko/guide/selectors)
|
|
87
|
+
- [Store 조합](https://violetflux.github.io/kerros/ko/guide/composition)
|
|
88
|
+
- [API](https://violetflux.github.io/kerros/ko/api/)
|
|
89
|
+
|
|
90
|
+
[MIT License](https://github.com/violetflux/kerros/blob/main/LICENSE)
|
package/README.md
CHANGED
|
@@ -1,39 +1,225 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://violetflux.github.io/kerros/">
|
|
3
|
+
<img src="https://raw.githubusercontent.com/violetflux/kerros/main/docs/public/banner.svg" alt="Kerros — selector-first React stores" width="100%" />
|
|
4
|
+
</a>
|
|
5
|
+
</p>
|
|
2
6
|
|
|
3
|
-
|
|
7
|
+
<p align="center">
|
|
8
|
+
English ·
|
|
9
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.zh-CN.md">简体中文</a> ·
|
|
10
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.ja.md">日本語</a> ·
|
|
11
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.ko.md">한국어</a> ·
|
|
12
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.de.md">Deutsch</a> ·
|
|
13
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.fr.md">Français</a> ·
|
|
14
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.es.md">Español</a>
|
|
15
|
+
</p>
|
|
4
16
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
17
|
+
<p align="center">
|
|
18
|
+
<a href="https://www.npmjs.com/package/@violetflux/kerros"><img src="https://img.shields.io/npm/v/@violetflux/kerros?color=7c3aed" alt="npm version" /></a>
|
|
19
|
+
<a href="https://github.com/violetflux/kerros/actions/workflows/ci.yml"><img src="https://github.com/violetflux/kerros/actions/workflows/ci.yml/badge.svg" alt="CI" /></a>
|
|
20
|
+
<a href="https://bundlephobia.com/package/@violetflux/kerros"><img src="https://img.shields.io/bundlephobia/minzip/@violetflux/kerros?label=gzip&color=2563eb" alt="minified gzip size" /></a>
|
|
21
|
+
<a href="https://github.com/violetflux/kerros/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@violetflux/kerros" alt="MIT license" /></a>
|
|
22
|
+
</p>
|
|
23
|
+
|
|
24
|
+
Kerros is a lightweight React state-sharing library based on Hooks and selectors.
|
|
25
|
+
|
|
26
|
+
Write state as an ordinary custom Hook, wrap it with `createStore`, and share it below a Provider. Each component selects only the fields it uses.
|
|
27
|
+
|
|
28
|
+
## Install
|
|
29
|
+
|
|
30
|
+
| Package manager | Command |
|
|
31
|
+
| --- | --- |
|
|
32
|
+
| npm | `npm install @violetflux/kerros` |
|
|
33
|
+
| pnpm | `pnpm add @violetflux/kerros` |
|
|
34
|
+
| Yarn | `yarn add @violetflux/kerros` |
|
|
35
|
+
| Bun | `bun add @violetflux/kerros` |
|
|
36
|
+
|
|
37
|
+
React 17, React 18, and React 19 are supported.
|
|
38
|
+
|
|
39
|
+
## Quick start
|
|
40
|
+
|
|
41
|
+
### Create a Store
|
|
42
|
+
|
|
43
|
+
Any custom Hook can become a Kerros Store:
|
|
8
44
|
|
|
9
45
|
```tsx
|
|
10
46
|
import { createStore } from '@violetflux/kerros'
|
|
11
47
|
import { useState } from 'react'
|
|
12
48
|
|
|
13
|
-
|
|
14
|
-
|
|
49
|
+
interface Task {
|
|
50
|
+
id: string
|
|
51
|
+
title: string
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const [useTask, TaskProvider] = createStore(() => {
|
|
55
|
+
const [tasks, setTasks] = useState<Task[]>([])
|
|
56
|
+
|
|
57
|
+
const addTask = (task: Task) => {
|
|
58
|
+
setTasks(v => [...v, task])
|
|
59
|
+
}
|
|
15
60
|
|
|
16
|
-
|
|
61
|
+
const finishTask = (taskId: string) => {
|
|
62
|
+
setTasks(v => v.filter(task => task.id !== taskId))
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return { tasks, addTask, finishTask }
|
|
17
66
|
})
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`createStore` returns two values: the Hook used by components and its matching Provider.
|
|
70
|
+
|
|
71
|
+
The Store is still a normal React Hook. It may use `useState`, `useReducer`, Context, SDK Hooks, or your own custom Hooks.
|
|
18
72
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
73
|
+
### Mount the Provider
|
|
74
|
+
|
|
75
|
+
Only descendants of `TaskProvider` may use `useTask`:
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
function App() {
|
|
79
|
+
return (
|
|
80
|
+
<TaskProvider>
|
|
81
|
+
<Header />
|
|
82
|
+
<TaskList />
|
|
83
|
+
</TaskProvider>
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Use the Store
|
|
89
|
+
|
|
90
|
+
Pass a selector that returns the fields used by the component:
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
function TaskList() {
|
|
94
|
+
const { tasks, finishTask } = useTask(s => ({
|
|
95
|
+
tasks: s.tasks,
|
|
96
|
+
finishTask: s.finishTask,
|
|
23
97
|
}))
|
|
24
98
|
|
|
25
|
-
return
|
|
99
|
+
return (
|
|
100
|
+
<ul>
|
|
101
|
+
{tasks.map(task => (
|
|
102
|
+
<li key={task.id}>
|
|
103
|
+
{task.title}
|
|
104
|
+
<button onClick={() => finishTask(task.id)}>Done</button>
|
|
105
|
+
</li>
|
|
106
|
+
))}
|
|
107
|
+
</ul>
|
|
108
|
+
)
|
|
26
109
|
}
|
|
27
110
|
```
|
|
28
111
|
|
|
29
|
-
Kerros
|
|
112
|
+
Kerros shallowly compares the selector object's top-level fields. When those selected fields stay equal, other Store updates do not rerender `TaskList`. The selector can stay inline and does not need `useCallback`.
|
|
30
113
|
|
|
31
|
-
|
|
114
|
+
## Why Kerros?
|
|
32
115
|
|
|
33
|
-
-
|
|
34
|
-
-
|
|
116
|
+
- **Just Hooks** — there are no reducers, actions, proxies, or new state syntax to learn
|
|
117
|
+
- **Focused rerenders** — a component updates only when the fields returned by its selector change
|
|
118
|
+
- **Provider scope** — mount a Store at the application root, inside a route, or around one widget
|
|
119
|
+
- **Multiple instances** — every mounted Provider creates an isolated Store instance
|
|
120
|
+
- **Store composition** — an inner Store can use an outer Store like any other Hook
|
|
121
|
+
- **React 17–19** — one package works across all three React generations
|
|
122
|
+
|
|
123
|
+
## Multiple instances
|
|
124
|
+
|
|
125
|
+
Each `TaskProvider` owns independent state:
|
|
126
|
+
|
|
127
|
+
```tsx
|
|
128
|
+
<TaskProvider>
|
|
129
|
+
<h2>Personal tasks</h2>
|
|
130
|
+
<TaskList />
|
|
131
|
+
</TaskProvider>
|
|
132
|
+
|
|
133
|
+
<TaskProvider>
|
|
134
|
+
<h2>Team tasks</h2>
|
|
135
|
+
<TaskList />
|
|
136
|
+
</TaskProvider>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Each `TaskList` automatically reads its nearest Provider.
|
|
140
|
+
|
|
141
|
+
## Store dependencies
|
|
142
|
+
|
|
143
|
+
A Store may call another Store directly. For example, a task Store can read the current account:
|
|
144
|
+
|
|
145
|
+
```tsx
|
|
146
|
+
export const [useTask, TaskProvider] = createStore(() => {
|
|
147
|
+
const { user } = useAccount(s => ({ user: s.user }))
|
|
148
|
+
const [tasks, setTasks] = useState<Task[]>([])
|
|
149
|
+
|
|
150
|
+
const addTask = (title: string) => {
|
|
151
|
+
if (!user)
|
|
152
|
+
return
|
|
153
|
+
|
|
154
|
+
setTasks(v => [...v, {
|
|
155
|
+
id: crypto.randomUUID(),
|
|
156
|
+
title,
|
|
157
|
+
assigneeId: user.id,
|
|
158
|
+
}])
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return { tasks, addTask }
|
|
162
|
+
})
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Mount Providers in dependency order and keep dependencies one-way:
|
|
166
|
+
|
|
167
|
+
```tsx
|
|
168
|
+
<AccountProvider>
|
|
169
|
+
<TaskProvider>
|
|
170
|
+
<App />
|
|
171
|
+
</TaskProvider>
|
|
172
|
+
</AccountProvider>
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Provider props
|
|
176
|
+
|
|
177
|
+
Provider props are passed to the Store Hook:
|
|
178
|
+
|
|
179
|
+
```tsx
|
|
180
|
+
interface CounterProps {
|
|
181
|
+
initialCount: number
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const [useCounter, CounterProvider] = createStore(
|
|
185
|
+
({ initialCount }: CounterProps) => {
|
|
186
|
+
const [count, setCount] = useState(initialCount)
|
|
187
|
+
return { count, setCount }
|
|
188
|
+
},
|
|
189
|
+
)
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
```tsx
|
|
193
|
+
<CounterProvider initialCount={42}>
|
|
194
|
+
<Counter />
|
|
195
|
+
</CounterProvider>
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## API
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
function createStore<TStore, TProps = Record<never, never>>(
|
|
202
|
+
useStoreValue: (props: TProps) => TStore,
|
|
203
|
+
): readonly [StoreHook<TStore>, StoreProvider<TProps>]
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
- `useStoreValue` follows the Rules of Hooks
|
|
207
|
+
- Provider props, excluding `children`, are passed to `useStoreValue`
|
|
208
|
+
- the returned Store Hook requires an object-returning selector
|
|
209
|
+
- using the Store Hook outside its matching Provider throws a clear error
|
|
210
|
+
- Provider instances work with Strict Mode and server rendering
|
|
211
|
+
|
|
212
|
+
Kerros uses the official `use-sync-external-store` shim for React 17 and prefers React's native implementation in React 18 and 19. React Compiler is optional.
|
|
213
|
+
|
|
214
|
+
## Documentation
|
|
215
|
+
|
|
216
|
+
- [Introduction](https://violetflux.github.io/kerros/guide/introduction)
|
|
217
|
+
- [Quick start](https://violetflux.github.io/kerros/guide/getting-started)
|
|
218
|
+
- [Selectors and rerenders](https://violetflux.github.io/kerros/guide/selectors)
|
|
219
|
+
- [Store dependencies](https://violetflux.github.io/kerros/guide/composition)
|
|
35
220
|
- [Migration from hox](https://violetflux.github.io/kerros/guide/migration)
|
|
221
|
+
- [API reference](https://violetflux.github.io/kerros/api/)
|
|
36
222
|
|
|
37
223
|
## License
|
|
38
224
|
|
|
39
|
-
MIT
|
|
225
|
+
[MIT](https://github.com/violetflux/kerros/blob/main/LICENSE)
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://violetflux.github.io/kerros/zh/">
|
|
3
|
+
<img src="https://raw.githubusercontent.com/violetflux/kerros/main/docs/public/banner.svg" alt="Kerros — selector 优先的 React Store" width="100%" />
|
|
4
|
+
</a>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.md">English</a> ·
|
|
9
|
+
简体中文 ·
|
|
10
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.ja.md">日本語</a> ·
|
|
11
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.ko.md">한국어</a> ·
|
|
12
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.de.md">Deutsch</a> ·
|
|
13
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.fr.md">Français</a> ·
|
|
14
|
+
<a href="https://github.com/violetflux/kerros/blob/main/README.es.md">Español</a>
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
Kerros 是一个基于 React Hook 和 selector 的轻量状态共享库。
|
|
18
|
+
|
|
19
|
+
你只需要用熟悉的 custom Hook 写状态,再用 `createStore` 包装一下,就能在 Provider 内的组件之间共享。每个组件通过 selector 选择自己使用的字段。
|
|
20
|
+
|
|
21
|
+
## 安装
|
|
22
|
+
|
|
23
|
+
| 包管理器 | 命令 |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| npm | `npm install @violetflux/kerros` |
|
|
26
|
+
| pnpm | `pnpm add @violetflux/kerros` |
|
|
27
|
+
| Yarn | `yarn add @violetflux/kerros` |
|
|
28
|
+
| Bun | `bun add @violetflux/kerros` |
|
|
29
|
+
|
|
30
|
+
支持 React 17、React 18 和 React 19。
|
|
31
|
+
|
|
32
|
+
## 快速上手
|
|
33
|
+
|
|
34
|
+
### 创建 Store
|
|
35
|
+
|
|
36
|
+
任意 custom Hook 都可以变成 Kerros Store:
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
import { createStore } from '@violetflux/kerros'
|
|
40
|
+
import { useState } from 'react'
|
|
41
|
+
|
|
42
|
+
interface Task {
|
|
43
|
+
id: string
|
|
44
|
+
title: string
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const [useTask, TaskProvider] = createStore(() => {
|
|
48
|
+
const [tasks, setTasks] = useState<Task[]>([])
|
|
49
|
+
|
|
50
|
+
const addTask = (task: Task) => {
|
|
51
|
+
setTasks(v => [...v, task])
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const finishTask = (taskId: string) => {
|
|
55
|
+
setTasks(v => v.filter(task => task.id !== taskId))
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return { tasks, addTask, finishTask }
|
|
59
|
+
})
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`createStore` 返回两个值:组件调用的 Hook 和对应的 Provider。
|
|
63
|
+
|
|
64
|
+
Store 仍然是普通 React Hook,可以继续使用 `useState`、`useReducer`、Context、SDK Hook 或其他 custom Hook。
|
|
65
|
+
|
|
66
|
+
### 挂载 Provider
|
|
67
|
+
|
|
68
|
+
只有 `TaskProvider` 的子节点可以调用 `useTask`:
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
function App() {
|
|
72
|
+
return (
|
|
73
|
+
<TaskProvider>
|
|
74
|
+
<Header />
|
|
75
|
+
<TaskList />
|
|
76
|
+
</TaskProvider>
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### 使用 Store
|
|
82
|
+
|
|
83
|
+
给 `useTask` 传入 selector,只返回组件使用的字段:
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
function TaskList() {
|
|
87
|
+
const { tasks, finishTask } = useTask(s => ({
|
|
88
|
+
tasks: s.tasks,
|
|
89
|
+
finishTask: s.finishTask,
|
|
90
|
+
}))
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<ul>
|
|
94
|
+
{tasks.map(task => (
|
|
95
|
+
<li key={task.id}>
|
|
96
|
+
{task.title}
|
|
97
|
+
<button onClick={() => finishTask(task.id)}>完成</button>
|
|
98
|
+
</li>
|
|
99
|
+
))}
|
|
100
|
+
</ul>
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Kerros 会浅比较 selector 返回对象的顶层字段。只要这些选中字段保持不变,Store 的其他更新就不会让 `TaskList` 重渲染。selector 可以直接写在调用位置,不需要 `useCallback`。
|
|
106
|
+
|
|
107
|
+
## 为什么用 Kerros
|
|
108
|
+
|
|
109
|
+
- **就是 Hook**:不需要学习 reducer、action、proxy 或新的状态语法
|
|
110
|
+
- **精确重渲染**:只有 selector 返回的字段变化时组件才更新
|
|
111
|
+
- **Provider 作用域**:Store 可以放在应用根部、路由内部或一个组件外层
|
|
112
|
+
- **多个实例**:每个 Provider 都会创建独立的 Store
|
|
113
|
+
- **Store 组合**:内层 Store 可以像普通 Hook 一样读取外层 Store
|
|
114
|
+
- **React 17–19**:同一个包兼容三个 React 大版本
|
|
115
|
+
|
|
116
|
+
## 多个实例
|
|
117
|
+
|
|
118
|
+
每个 `TaskProvider` 都拥有独立状态:
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
<TaskProvider>
|
|
122
|
+
<h2>个人任务</h2>
|
|
123
|
+
<TaskList />
|
|
124
|
+
</TaskProvider>
|
|
125
|
+
|
|
126
|
+
<TaskProvider>
|
|
127
|
+
<h2>团队任务</h2>
|
|
128
|
+
<TaskList />
|
|
129
|
+
</TaskProvider>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
每个 `TaskList` 会自动读取离自己最近的 Provider。
|
|
133
|
+
|
|
134
|
+
## Store 之间的依赖
|
|
135
|
+
|
|
136
|
+
一个 Store 可以直接调用另一个 Store。例如任务 Store 读取当前账户:
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
export const [useTask, TaskProvider] = createStore(() => {
|
|
140
|
+
const { user } = useAccount(s => ({ user: s.user }))
|
|
141
|
+
const [tasks, setTasks] = useState<Task[]>([])
|
|
142
|
+
|
|
143
|
+
const addTask = (title: string) => {
|
|
144
|
+
if (!user)
|
|
145
|
+
return
|
|
146
|
+
|
|
147
|
+
setTasks(v => [...v, {
|
|
148
|
+
id: crypto.randomUUID(),
|
|
149
|
+
title,
|
|
150
|
+
assigneeId: user.id,
|
|
151
|
+
}])
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return { tasks, addTask }
|
|
155
|
+
})
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
按依赖顺序挂 Provider,并保持单向依赖:
|
|
159
|
+
|
|
160
|
+
```tsx
|
|
161
|
+
<AccountProvider>
|
|
162
|
+
<TaskProvider>
|
|
163
|
+
<App />
|
|
164
|
+
</TaskProvider>
|
|
165
|
+
</AccountProvider>
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Provider props
|
|
169
|
+
|
|
170
|
+
Provider props 会传给 Store Hook:
|
|
171
|
+
|
|
172
|
+
```tsx
|
|
173
|
+
interface CounterProps {
|
|
174
|
+
initialCount: number
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const [useCounter, CounterProvider] = createStore(
|
|
178
|
+
({ initialCount }: CounterProps) => {
|
|
179
|
+
const [count, setCount] = useState(initialCount)
|
|
180
|
+
return { count, setCount }
|
|
181
|
+
},
|
|
182
|
+
)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
```tsx
|
|
186
|
+
<CounterProvider initialCount={42}>
|
|
187
|
+
<Counter />
|
|
188
|
+
</CounterProvider>
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## API
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
function createStore<TStore, TProps = Record<never, never>>(
|
|
195
|
+
useStoreValue: (props: TProps) => TStore,
|
|
196
|
+
): readonly [StoreHook<TStore>, StoreProvider<TProps>]
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
- `useStoreValue` 必须遵守 Hooks 规则
|
|
200
|
+
- 除 `children` 外的 Provider props 会传给 `useStoreValue`
|
|
201
|
+
- Store Hook 必须接收一个返回对象的 selector
|
|
202
|
+
- 在对应 Provider 外调用会抛出明确错误
|
|
203
|
+
- 支持 Strict Mode、服务端渲染和 Provider 多实例
|
|
204
|
+
|
|
205
|
+
React 17 使用官方 `use-sync-external-store` shim;React 18 和 19 可用时优先使用 React 原生实现。React Compiler 不是必需项。
|
|
206
|
+
|
|
207
|
+
## 文档
|
|
208
|
+
|
|
209
|
+
- [介绍](https://violetflux.github.io/kerros/zh/guide/introduction)
|
|
210
|
+
- [快速上手](https://violetflux.github.io/kerros/zh/guide/getting-started)
|
|
211
|
+
- [Selector 与重渲染](https://violetflux.github.io/kerros/zh/guide/selectors)
|
|
212
|
+
- [Store 之间的依赖](https://violetflux.github.io/kerros/zh/guide/composition)
|
|
213
|
+
- [从 hox 迁移](https://violetflux.github.io/kerros/zh/guide/migration)
|
|
214
|
+
- [API 参考](https://violetflux.github.io/kerros/zh/api/)
|
|
215
|
+
|
|
216
|
+
## 许可证
|
|
217
|
+
|
|
218
|
+
[MIT](https://github.com/violetflux/kerros/blob/main/LICENSE)
|
package/package.json
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@violetflux/kerros",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "A tiny selector-first React store built on useSyncExternalStore.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
7
|
+
"react-hooks",
|
|
8
|
+
"react-context",
|
|
7
9
|
"state-management",
|
|
8
10
|
"store",
|
|
9
11
|
"selector",
|
|
12
|
+
"external-store",
|
|
10
13
|
"use-sync-external-store"
|
|
11
14
|
],
|
|
12
15
|
"homepage": "https://violetflux.github.io/kerros/",
|