@t8/react-store 1.0.23 → 1.0.25

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.
Files changed (2) hide show
  1. package/README.md +54 -30
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -16,25 +16,24 @@ Installation: `npm i @t8/react-store`
16
16
  Moving the local state to the full-fledged shared state:
17
17
 
18
18
  ```diff
19
- import { createContext, useContext } from "react";
20
19
  + import { Store, useStore } from "@t8/react-store";
21
20
  +
22
- + let AppContext = createContext(new Store(0));
21
+ + let counterStore = new Store(0);
23
22
 
24
23
  let Counter = () => {
25
24
  - let [counter, setCounter] = useState(0);
26
- + let [counter, setCounter] = useStore(useContext(AppContext));
25
+ + let [counter, setCounter] = useStore(counterStore);
27
26
 
28
27
  let handleClick = () => {
29
28
  setCounter(value => value + 1);
30
29
  };
31
30
 
32
- return <button onClick={handleClick}>{counter}</button>;
31
+ return <button onClick={handleClick}>+ {counter}</button>;
33
32
  };
34
33
 
35
34
  let ResetButton = () => {
36
35
  - let [, setCounter] = useState(0);
37
- + let [, setCounter] = useStore(useContext(AppContext), false);
36
+ + let [, setCounter] = useStore(counterStore, false);
38
37
 
39
38
  let handleClick = () => {
40
39
  setCounter(0);
@@ -46,27 +45,20 @@ Moving the local state to the full-fledged shared state:
46
45
  let App = () => <><Counter/>{" "}<ResetButton/></>;
47
46
  ```
48
47
 
49
- [Live counter demo](https://codesandbox.io/p/sandbox/rtng37?file=%2Fsrc%2FPlusButton.jsx)<br>
48
+ [Live counter demo](https://codesandbox.io/p/sandbox/szhdnw?file=%252Fsrc%252FApp.tsx)<br>
50
49
  [Tic-tac-toe](https://codesandbox.io/p/sandbox/tq852v?file=%252Fsrc%252FApp.tsx)
51
50
 
52
51
  🔹 The shared state setup shown above is very similar to `useState()` allowing for quick migration from local state to shared state or the other way around.
53
52
 
54
53
  🔹 The `false` parameter in `useStore(store, false)` (as in `<ResetButton>` above) tells the hook not to subscribe the component to tracking the store state updates. The common use case is when a component makes use of the store state setter without using the store state value.
55
54
 
56
- 🔹 Note that updating the store state doesn't change the store reference sitting in the React Context and therefore doesn't cause updates of the entire React Context. Only the components subscribed to store state updates by means of `useStore()` will be notified to re-render.
55
+ 🔹 Similarly to instances of the built-in data container classes, such as `Set` and `Map`, stores are created as `new Store(data)` rather than with a factory function.
57
56
 
58
57
  ## Single store or multiple stores
59
58
 
60
- An application can have as many stores as needed, whether on a single React Context or multiple Contexts.
59
+ An application can have as many stores as needed.
61
60
 
62
- ```js
63
- let AppContext = createContext({
64
- users: new Store(/* ... */),
65
- items: new Store(/* ... */),
66
- });
67
- ```
68
-
69
- 🔹 Splitting data into multiple stores helps maintain more targeted subscriptions to data changes in components.
61
+ 🔹 Splitting data into multiple stores is one of the strategies to maintain more targeted subscriptions to data changes in components. The other strategy is filtering store updates at the component level, which is discussed below.
70
62
 
71
63
  ## Filtering store updates
72
64
 
@@ -76,7 +68,7 @@ When only the store state setter is required, without the store state value, we
76
68
  let [, setState] = useState(store, false);
77
69
  ```
78
70
 
79
- Apart from a boolean, `useStore(store, shouldUpdate)` can take a function of `(nextState, prevState) => boolean` as the second parameter to filter store updates to respond to:
71
+ Apart from a boolean, `useStore(store, shouldUpdate)` accepts a function of `(nextState, prevState) => boolean` as the second parameter to filter store updates to respond to:
80
72
 
81
73
  ```jsx
82
74
  let ItemCard = ({ id }) => {
@@ -86,10 +78,7 @@ let ItemCard = ({ id }) => {
86
78
  return nextItems[id].revision !== prevItems[id].revision;
87
79
  }, [id]);
88
80
 
89
- let [items, setItems] = useStore(
90
- useContext(AppContext).items,
91
- hasRelevantUpdates,
92
- );
81
+ let [items, setItems] = useStore(itemStore, hasRelevantUpdates);
93
82
 
94
83
  return (
95
84
  // Content
@@ -101,15 +90,50 @@ let ItemCard = ({ id }) => {
101
90
 
102
91
  Shared state can be provided to the app by means of a regular React Context provider:
103
92
 
104
- ```diff
105
- let App = () => (
106
- - <AppContext.Provider value={42}>
107
- + <AppContext.Provider value={new Store(42)}>
108
- <PlusButton/>{" "}<Display/>
109
- </AppContext.Provider>
110
- );
93
+ ```ts
94
+ import { createContext } from "react";
95
+
96
+ export let AppContext = createContext(new Store(0));
97
+ ```
98
+
99
+ ```tsx
100
+ let App = () => (
101
+ <AppContext.Provider value={new Store(42)}>
102
+ <PlusButton/>{" "}<Display/>
103
+ </AppContext.Provider>
104
+ );
105
+ ```
106
+
107
+ ```tsx
108
+ let Counter = () => {
109
+ let [counter, setCounter] = useStore(useContext(AppContext));
110
+
111
+ // Rendering
112
+ };
111
113
  ```
112
114
 
115
+ [Live counter demo with Context](https://codesandbox.io/p/sandbox/rtng37?file=%2Fsrc%2FPlusButton.jsx)
116
+
117
+ 🔹 In a multi-store setup, stores can be located in a single Context or split across multiple Contexts, just like any application data.
118
+
119
+ ```js
120
+ // Multiple stores in a single Context
121
+ let AppContext = createContext({
122
+ users: new Store(/* ... */),
123
+ items: new Store(/* ... */),
124
+ });
125
+ ```
126
+
127
+ ```jsx
128
+ let ItemCard = ({ id }) => {
129
+ let [items, setItems] = useStore(useContext(AppContext).items);
130
+
131
+ // Rendering
132
+ };
133
+ ```
134
+
135
+ 🔹 Note that updating the store state doesn't change the store reference sitting in the React Context and therefore doesn't cause updates of the entire Context. Only the components subscribed to updates in the particular store by means of `useStore(store)` will be notified to re-render.
136
+
113
137
  ## Store data
114
138
 
115
139
  A store can contain data of any type.
@@ -128,6 +152,6 @@ Immer can be used with `useStore()` just the same way as [with `useState()`](htt
128
152
 
129
153
  The ready-to-use hook from the [T8 React Pending](https://github.com/t8js/react-pending) package helps manage shared async action state without disturbing the app's state management and actions' code.
130
154
 
131
- ## Standalone store
155
+ ## Remount-persistent state
132
156
 
133
- A store initialized outside a component can be used as the component's remount-persistent state.
157
+ A standalone store initialized outside a component can be used by the component as remount-persistent state, whether used by other components or not.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@t8/react-store",
3
- "version": "1.0.23",
3
+ "version": "1.0.25",
4
4
  "description": "Concise shared state management for React apps",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -44,6 +44,6 @@
44
44
  "typescript": "^5.9.3"
45
45
  },
46
46
  "dependencies": {
47
- "@t8/store": "^1.1.4"
47
+ "@t8/store": "^1.1.5"
48
48
  }
49
49
  }