@webkrafters/react-observable-context 4.1.0-alpha.0 → 4.1.0-alpha.2
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.md +155 -156
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -80,14 +80,7 @@ A property path is a dot-notation string leading to a specific property within a
|
|
|
80
80
|
<strong id="property-path-example">Ex. Given the following object:</strong>
|
|
81
81
|
|
|
82
82
|
```jsx
|
|
83
|
-
{
|
|
84
|
-
a: {
|
|
85
|
-
c: {
|
|
86
|
-
e: 5,
|
|
87
|
-
f: [ 0, 2, 4 ]
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
83
|
+
{ a: { c: { e: 5, f: [ 0, 2, 4 ] } } }
|
|
91
84
|
```
|
|
92
85
|
The property path `a.c.e` accesses the `e=5` property.<br />
|
|
93
86
|
Either of the property paths `a.c.f.1` and `a.c.f[1]` accesses the `[1]=2` property.<br />
|
|
@@ -112,29 +105,28 @@ A selector map is an object holding key:value pairs.<br />
|
|
|
112
105
|
```jsx
|
|
113
106
|
// Given the following state object:
|
|
114
107
|
const state = {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
z: 9
|
|
124
|
-
} ]
|
|
125
|
-
}
|
|
108
|
+
a: 1, b: 2, c: 3, d: {
|
|
109
|
+
e: 5,
|
|
110
|
+
f: [ 6, {
|
|
111
|
+
x: 7,
|
|
112
|
+
y: 8,
|
|
113
|
+
z: 9
|
|
114
|
+
} ]
|
|
115
|
+
}
|
|
126
116
|
};
|
|
117
|
+
|
|
127
118
|
// a client observing the following selector map
|
|
128
119
|
const selectorMap = {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
120
|
+
all: '@@STATE',
|
|
121
|
+
myData: 'd',
|
|
122
|
+
secondFElement: 'd.f[1]'
|
|
132
123
|
};
|
|
124
|
+
|
|
133
125
|
// will receive the following store data
|
|
134
126
|
store.data = {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
127
|
+
all: state,
|
|
128
|
+
myData: state.d,
|
|
129
|
+
secondFElement: state.d.f[1]
|
|
138
130
|
}
|
|
139
131
|
```
|
|
140
132
|
|
|
@@ -208,50 +200,52 @@ store.setState({ ...state, a: { ...state.a, b: [ { ...first, y: 30 }, 22, ...res
|
|
|
208
200
|
```
|
|
209
201
|
|
|
210
202
|
<h3 id="setstate-tags"><b><i><u>Rewriting state using tag commands</u></i></b></h3>
|
|
211
|
-
By default setState merges new changes into
|
|
203
|
+
By default, <code>store.setState</code> recursively merges new changes into current state.<br />
|
|
204
|
+
To overwrite current state slices with new values, <b>7</b> tag commands have been provided:
|
|
212
205
|
<ol>
|
|
213
|
-
<li><span style="margin-left: 10px"><b><
|
|
214
|
-
<li><span style="margin-left: 10px"><b><
|
|
215
|
-
<li><span style="margin-left: 10px"><b><
|
|
216
|
-
<li><span style="margin-left: 10px"><b><
|
|
217
|
-
<li><span style="margin-left: 10px"><b><
|
|
218
|
-
<li><span style="margin-left: 10px"><b><
|
|
219
|
-
<li><span style="margin-left: 10px"><b><
|
|
206
|
+
<li><span style="margin-left: 10px"><b style="margin-right: 6px"><i>@@CLEAR:</i></b> sets state slice to its corresponding empty value</span></li>
|
|
207
|
+
<li><span style="margin-left: 10px"><b style="margin-right: 6px"><i>@@DELETE:</i></b> removes plain object properties and array items</span></li>
|
|
208
|
+
<li><span style="margin-left: 10px"><b style="margin-right: 6px"><i>@@MOVE:</i></b> moves array elements</span></li>
|
|
209
|
+
<li><span style="margin-left: 10px"><b style="margin-right: 6px"><i>@@PUSH:</i></b> pushes new items into an array</span></li>
|
|
210
|
+
<li><span style="margin-left: 10px"><b style="margin-right: 6px"><i>@@REPLACE:</i></b> replaces property values</span></li>
|
|
211
|
+
<li><span style="margin-left: 10px"><b style="margin-right: 6px"><i>@@SET:</i></b> sets property values</span></li>
|
|
212
|
+
<li><span style="margin-left: 10px"><b style="margin-right: 6px"><i>@@SPLICE:</i></b> splices array items</span></li>
|
|
220
213
|
</ol>
|
|
221
|
-
<
|
|
214
|
+
<b>Examples:</b><br /><br />
|
|
222
215
|
|
|
223
|
-
<b
|
|
216
|
+
<i><b>@@CLEAR:</b> (takes no arguments)</i>
|
|
224
217
|
|
|
225
218
|
```jsx
|
|
226
219
|
const state = {
|
|
227
|
-
|
|
228
|
-
|
|
220
|
+
a: { b: [{ x: 7, y: 8, z: 9 }, { x: 17, y: 18, z: 19 }] },
|
|
221
|
+
j: 10
|
|
229
222
|
};
|
|
230
223
|
|
|
231
|
-
|
|
224
|
+
/* empties the state; sets state = {} */
|
|
225
|
+
store.setState( '@@CLEAR' ) // or store.setState({ '@@CLEAR': <anything> })
|
|
232
226
|
|
|
233
227
|
/* empties the value at state.a.b; sets state.a.b = [] */
|
|
234
|
-
store.setState({ a: { b: '@@CLEAR' } }) // or store.setState({ a: { b: { @@CLEAR: <anything> } } })
|
|
228
|
+
store.setState({ a: { b: '@@CLEAR' } }) // or store.setState({ a: { b: { '@@CLEAR': <anything> } } })
|
|
235
229
|
|
|
236
230
|
/* empties the value at state.a.j; sets state.a.j = null */
|
|
237
|
-
store.setState({ a: { j: '@@CLEAR' } }) // or store.setState({ a: { j: { @@CLEAR: <anything> } } })
|
|
231
|
+
store.setState({ a: { j: '@@CLEAR' } }) // or store.setState({ a: { j: { '@@CLEAR': <anything> } } })
|
|
238
232
|
|
|
239
233
|
/* empties the value at state.a.b[ 0 ]; sets state.a.b = [{}] */
|
|
240
|
-
store.setState({ a: { b: [ '@@CLEAR' ] } }) // or store.setState({ a: { b: [ { @@CLEAR: <anything> } ] } })
|
|
234
|
+
store.setState({ a: { b: [ '@@CLEAR' ] } }) // or store.setState({ a: { b: [ { '@@CLEAR': <anything> } ] } })
|
|
241
235
|
|
|
242
236
|
/* empties the value at state.a.b[0]; sets state.a.b = [{}, state.a.b[1]] */
|
|
243
|
-
store.setState({ a: { b: [ '@@CLEAR', state.a.b[1] ] } }) // or store.setState({ a: { b: [ { @@CLEAR: <anything> }, state.a.b[1] ] } })
|
|
237
|
+
store.setState({ a: { b: [ '@@CLEAR', state.a.b[1] ] } }) // or store.setState({ a: { b: [ { '@@CLEAR': <anything> }, state.a.b[1] ] } })
|
|
244
238
|
|
|
245
239
|
/* empties the value at state.a.b[0]; sets state.a.b = [{}, a.b[1]] using indexing (RECOMMENDED) */
|
|
246
|
-
store.setState({ a: { b: { 0: '@@CLEAR' } } }) // or store.setState({ a: { b: { 0: { @@CLEAR: <anything> } } } })
|
|
240
|
+
store.setState({ a: { b: { 0: '@@CLEAR' } } }) // or store.setState({ a: { b: { 0: { '@@CLEAR': <anything> } } } })
|
|
247
241
|
```
|
|
248
242
|
|
|
249
|
-
<b
|
|
243
|
+
<i><b>@@DELETE:</b> (takes an array argument listing property keys to delete)</i>
|
|
250
244
|
|
|
251
245
|
```jsx
|
|
252
246
|
const state = {
|
|
253
|
-
|
|
254
|
-
|
|
247
|
+
a: { b: [{ x: 7, y: 8, z: 9 }, { x: 17, y: 18, z: 19 }] },
|
|
248
|
+
j: 10
|
|
255
249
|
};
|
|
256
250
|
|
|
257
251
|
store.setState({ '@@DELETE': [ 'a' ] }) // removes state.a; sets state = {j: 10}
|
|
@@ -268,16 +262,16 @@ store.setState({ a: { b: [ state.a.b[ 0 ], { '@@DELETE': [ 'x', 'z' ] } ] } })
|
|
|
268
262
|
store.setState({ a: { b: { 1: { '@@DELETE': [ 'x', 'z' ] } } } })
|
|
269
263
|
```
|
|
270
264
|
|
|
271
|
-
<b
|
|
265
|
+
<i><b>@@MOVE:</b> (takes an array argument listing: -/+fromIndex, -/+toIndex and optional +numItems?. numItems = 1 by default)</i>
|
|
272
266
|
|
|
273
267
|
```jsx
|
|
274
268
|
const state = {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
269
|
+
a: { b: [{ x: 7, y: 8, z: 9 }, { x: 17, y: 18, z: 19 }] },
|
|
270
|
+
j: 10,
|
|
271
|
+
q: [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
|
|
278
272
|
};
|
|
279
273
|
|
|
280
|
-
store.setState({ a: { '@@MOVE': [ 0, 1 ] } }) // assigning a @@MOVE command to a non-array property has no effect.
|
|
274
|
+
store.setState({ a: { '@@MOVE': [ 0, 1 ] } }) // assigning a '@@MOVE' command to a non-array property has no effect.
|
|
281
275
|
|
|
282
276
|
/* moves state.a.b[0] into index 1; leaving state.a.b = [{ x: 17, y: 18, z: 19 }, { x: 7, y: 8, z: 9 }] */
|
|
283
277
|
store.setState({ a: { b: { '@@MOVE': [ 0, 1 ] } } }) // or store.setState({ a: { b: { '@@MOVE': [ -2, -1 ] } } })
|
|
@@ -286,26 +280,26 @@ store.setState({ a: { b: { '@@MOVE': [ 0, 1 ] } } }) // or store.setState({ a: {
|
|
|
286
280
|
store.setState({ a: { q: { '@@MOVE': [ 4, 1, 4 ] } } }) // or store.setState({ a: { q: { '@@MOVE': [ -5, -8, 4 ] } } })
|
|
287
281
|
```
|
|
288
282
|
|
|
289
|
-
<b
|
|
283
|
+
<i><b>@@PUSH:</b> (takes an array argument listing new values to append)</i>
|
|
290
284
|
|
|
291
285
|
```jsx
|
|
292
286
|
const state = {
|
|
293
|
-
|
|
294
|
-
|
|
287
|
+
a: { b: [{ x: 7, y: 8, z: 9 }, { x: 17, y: 18, z: 19 }] },
|
|
288
|
+
j: 10
|
|
295
289
|
};
|
|
296
290
|
|
|
297
|
-
store.setState({ a: { '@@PUSH': [{ n: 5 }] } }) // assigning a @@PUSH command to a non-array property has no effect.
|
|
291
|
+
store.setState({ a: { '@@PUSH': [{ n: 5 }] } }) // assigning a '@@PUSH' command to a non-array property has no effect.
|
|
298
292
|
|
|
299
293
|
/* appends 2 new items into state.a.b; leaving state.a.b = [...state.a.b, { x: 27, y: 28, z: 29 }, { x: 37, y: 38, z: 39 }] */
|
|
300
294
|
store.setState({ a: { b: { '@@PUSH': [{ x: 27, y: 28, z: 29 }, { x: 37, y: 38, z: 39 }] } } })
|
|
301
295
|
```
|
|
302
296
|
|
|
303
|
-
<b
|
|
297
|
+
<i><b>@@REPLACE:</b> (takes an argument holding the replacment value)</i>
|
|
304
298
|
|
|
305
299
|
```jsx
|
|
306
300
|
const state = {
|
|
307
|
-
|
|
308
|
-
|
|
301
|
+
a: { b: [{ x: 7, y: 8, z: 9 }, { x: 17, y: 18, z: 19 }] },
|
|
302
|
+
j: 10
|
|
309
303
|
};
|
|
310
304
|
|
|
311
305
|
store.setState({ '@@REPLACE': { a: 'Demo', j: 17 } }) // rewrites state to { a: 'Demo', j: 17 };
|
|
@@ -319,18 +313,20 @@ store.setState({ a: { b: [ state.a.b[ 0 ], { '@@REPLACE': { x: 97, y: 98, z: 99
|
|
|
319
313
|
store.setState({ a: { b: { 1: { '@@REPLACE': { x: 97, y: 98, z: 99 } } } } })
|
|
320
314
|
```
|
|
321
315
|
|
|
322
|
-
<b
|
|
316
|
+
<i><b>@@SET:</b> (takes an argument holding either the replacment value or a compute function returning the replacement value)</i>
|
|
323
317
|
|
|
324
318
|
```jsx
|
|
325
319
|
/*
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
320
|
+
This tag is for handling edge cases only. Please use sparingly. In most cases, store.setState with or without any of the other tags is sufficient and most efficient.
|
|
321
|
+
|
|
322
|
+
This and the '@@REPLACE' tags are functionally equivalent when used with a replacement value argument.
|
|
323
|
+
|
|
324
|
+
Be aware that the compute function argument may be `undefined` for properties which do not yet exist in the state.
|
|
329
325
|
*/
|
|
330
326
|
|
|
331
327
|
const state = {
|
|
332
|
-
|
|
333
|
-
|
|
328
|
+
a: { b: [{ x: 7, y: 8, z: 9 }, { x: 17, y: 18, z: 19 }] },
|
|
329
|
+
j: 10
|
|
334
330
|
};
|
|
335
331
|
|
|
336
332
|
store.setState({ '@@SET': currentValue => ({ ...currentValue, a: 'Demo', j: 17 }) }) // rewrites state to { ...state, a: 'Demo', j: 17 };
|
|
@@ -342,60 +338,58 @@ store.setState({ a: { b: [ state.a.b[ 0 ], { '@@SET': currentValue => ({ ...curr
|
|
|
342
338
|
|
|
343
339
|
/* rewrites state.a.b[1] to { x: 97, y: 98, z: 99 }; leaving state.a.b = [{ x: 7, y: 8, z: 9 }, { x: 97, y: 98, z: 99 }] using indexing (RECOMMENDED) */
|
|
344
340
|
store.setState({ a: { b: { 1: { '@@SET': currentValue => ({ ...currentValue, x: 97, y: 98, z: 99 }) } } } })
|
|
345
|
-
|
|
346
|
-
/** be aware: currentValue may be `undefined` when adding new state slice properties. */
|
|
347
341
|
```
|
|
348
342
|
|
|
349
|
-
<b
|
|
343
|
+
<i><b>@@SPLICE:</b> (takes an array argument listing: -/+fromIndex, +deleteCount and optional ...newItems? newItems = ...[] by default)</i>
|
|
350
344
|
|
|
351
345
|
```jsx
|
|
352
346
|
const state = {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
347
|
+
a: { b: [{ x: 7, y: 8, z: 9 }, { x: 17, y: 18, z: 19 }] },
|
|
348
|
+
j: 10,
|
|
349
|
+
q: [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
|
|
356
350
|
};
|
|
357
351
|
|
|
358
|
-
store.setState({ a: { '@@SPLICE': [ 0, 1 ] } }) // assigning a @@SPLICE command to a non-array property has no effect.
|
|
352
|
+
store.setState({ a: { '@@SPLICE': [ 0, 1 ] } }) // assigning a '@@SPLICE' command to a non-array property has no effect.
|
|
359
353
|
|
|
360
354
|
/* removes state.a.b[0]; leaving state.a.b = [{ x: 17, y: 18, z: 19 }] */
|
|
361
|
-
store.setState({ a: { b: { '@@SPLICE': [ 0, 1 ] } } }) // or store.setState({ a: { b: { SPLICE': [ -2, -1 ] } } })
|
|
355
|
+
store.setState({ a: { b: { '@@SPLICE': [ 0, 1 ] } } }) // or store.setState({ a: { b: { '@@SPLICE': [ -2, -1 ] } } })
|
|
362
356
|
|
|
363
357
|
/* replaces state.q[4] - [7] with 2 items; leaving state.q = [ 1, 2, 3, 4, 33, 88, 9 ] */
|
|
364
358
|
store.setState({ a: { q: { '@@SPLICE': [ 4, 4, 33, 88 ] } } }) // or store.setState({ a: { q: { '@@SPLICE': [ -5, 4, 33, 88 ] } } })
|
|
365
359
|
```
|
|
366
360
|
|
|
367
|
-
<b><
|
|
361
|
+
<h3><b><i>Combination Usage:</i></b></h3>
|
|
368
362
|
|
|
369
|
-
These tags may be used in combination with the default usage where all
|
|
363
|
+
These tags may be used in combination with the default usage where all top-level tag command results in property are sequentially merged into state followed by the merging of the rest of the property changes.
|
|
370
364
|
|
|
371
365
|
<strong>Example:</strong>
|
|
372
366
|
|
|
373
367
|
```jsx
|
|
374
368
|
const state = {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
369
|
+
a: { b: [{ x: 7, y: 8, z: 9 }, { x: 17, y: 18, z: 19 }] },
|
|
370
|
+
j: 10,
|
|
371
|
+
q: [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
|
|
378
372
|
};
|
|
379
373
|
|
|
380
374
|
store.setState({
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
375
|
+
a: {
|
|
376
|
+
b: {
|
|
377
|
+
/* evaluated 1st */ '@@DELETE': [ 0 ], // upon deleting state.a.b[0] -> state.a.b[1] becomes the new state.a.b[0]
|
|
378
|
+
/* evaluated 3rd */ 0: '@@CLEAR', // clear the new state.a.b[0]
|
|
379
|
+
/* evaluated 4th */ 2: { x: 47, y: 48, z: 49 }, // add new item at state.a.b[2],
|
|
380
|
+
/* evaluated 2md */ '@@PUSH': [{ x: 107, y: 108, z: 109 }] // appends state.a.b[1]
|
|
381
|
+
}
|
|
382
|
+
},
|
|
383
|
+
j: { '@@SET': currentValue => currentValue < 10 ? currentValue : 0 },
|
|
384
|
+
q: {
|
|
385
|
+
/* evaluated 1st */ '@@MOVE': [ 5, 3, 2 ],
|
|
386
|
+
/* evaluated 2md */ 12: 11
|
|
387
|
+
}
|
|
394
388
|
})
|
|
395
389
|
// => {
|
|
396
|
-
//
|
|
397
|
-
//
|
|
398
|
-
//
|
|
390
|
+
// a: { b: [{}, { x: 107, y: 108, z: 109 }, { x: 47, y: 48, z: 49 }] },
|
|
391
|
+
// j: 0,
|
|
392
|
+
// q: [ 1, 2, 3, 6, 7, 4, 5, 8, 9, <empty>, <empty>, <empty>, 11 ]
|
|
399
393
|
// }
|
|
400
394
|
```
|
|
401
395
|
|
|
@@ -444,13 +438,15 @@ The React-Observable-Context module contains **4** exports namely:
|
|
|
444
438
|
|
|
445
439
|
# Usage
|
|
446
440
|
|
|
447
|
-
<i><b
|
|
441
|
+
<i><u><b>context.js</b></u></i>
|
|
442
|
+
|
|
448
443
|
```jsx
|
|
449
444
|
import { createContext } from '@webkrafters/react-observable-context';
|
|
450
445
|
export default createContext();
|
|
451
446
|
```
|
|
452
447
|
|
|
453
|
-
<i><b
|
|
448
|
+
<i><u><b>ui.js</b></u> (connect method)</i>
|
|
449
|
+
|
|
454
450
|
```jsx
|
|
455
451
|
import React, { useCallback, useEffect } from 'react';
|
|
456
452
|
import { connect } from '@webkrafters/react-observable-context';
|
|
@@ -458,13 +454,13 @@ import ObservableContext from './context';
|
|
|
458
454
|
|
|
459
455
|
export const YearText = ({ data }) => ( <div>Year: { data.year }</div> );
|
|
460
456
|
export const YearInput = ({ data, setState, resetState }) => {
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
457
|
+
const onChange = useCallback( e => setState({
|
|
458
|
+
a: { b: { x: { y: { z: { 0: e.target.value } } } } }
|
|
459
|
+
}), [ setState ]);
|
|
460
|
+
useEffect(() => {
|
|
461
|
+
data.year > 2049 && resetState([ 'a.b.c' ]);
|
|
462
|
+
}, [ data.year ]);
|
|
463
|
+
return ( <div>Year: <input type="number" onChange={ onChange } /> );
|
|
468
464
|
};
|
|
469
465
|
|
|
470
466
|
const withConnector = connect( ObservablContext, { year: 'a.b.x.y.z[0]' } );
|
|
@@ -472,16 +468,17 @@ const Client1 = withConnector( YearText );
|
|
|
472
468
|
const Client2 = withConnector( YearInput );
|
|
473
469
|
|
|
474
470
|
const Ui = () => (
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
471
|
+
<div>
|
|
472
|
+
<Client1 />
|
|
473
|
+
<Client2 />
|
|
474
|
+
</div>
|
|
479
475
|
);
|
|
480
476
|
|
|
481
477
|
export default Ui;
|
|
482
478
|
```
|
|
483
479
|
|
|
484
|
-
<i><b
|
|
480
|
+
<i><u><b>ui.js</b></u> (useContext with memo method)</i>
|
|
481
|
+
|
|
485
482
|
```jsx
|
|
486
483
|
import React, { memo, useCallback, useEffect } from 'react';
|
|
487
484
|
import { useContext } from '@webkrafters/react-observable-context';
|
|
@@ -490,32 +487,33 @@ import ObservableContext from './context';
|
|
|
490
487
|
const selectorMap = { year: 'a.b.x.y.z[0]' };
|
|
491
488
|
|
|
492
489
|
const Client1 = memo(() => { // memoize to prevent 'no-change' renders from the parent.
|
|
493
|
-
|
|
494
|
-
|
|
490
|
+
const { data } = useContext( ObservableContext, selectorMap );
|
|
491
|
+
return ( <div>Year: { data.year }</div> );
|
|
495
492
|
});
|
|
496
493
|
|
|
497
494
|
const Client2 = memo(() => { // memoize to prevent 'no-change' renders from the parent.
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
495
|
+
const { data, setState, resetState } = useContext( ObservableContext, selectorMap );
|
|
496
|
+
const onChange = useCallback( e => setState({
|
|
497
|
+
a: { b: { x: { y: { z: { 0: e.target.value } } } } }
|
|
498
|
+
}), [ setState ]);
|
|
499
|
+
useEffect(() => {
|
|
500
|
+
data.year > 2049 && resetState([ 'a.b.c' ]);
|
|
501
|
+
}, [ data.year ]);
|
|
502
|
+
return ( <div>Year: <input type="number" onChange={ onChange } /> );
|
|
506
503
|
});
|
|
507
504
|
|
|
508
505
|
const Ui = () => (
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
506
|
+
<div>
|
|
507
|
+
<Client1 />
|
|
508
|
+
<Client2 />
|
|
509
|
+
</div>
|
|
513
510
|
);
|
|
514
511
|
|
|
515
512
|
export default Ui;
|
|
516
513
|
```
|
|
517
514
|
|
|
518
515
|
<i id="provider-usage"><b><u>provider.js</u></b></i>
|
|
516
|
+
|
|
519
517
|
```jsx
|
|
520
518
|
import React, { useEffect, useState } from 'react';
|
|
521
519
|
import ObservableContext from './context';
|
|
@@ -524,47 +522,47 @@ import Ui from './ui';
|
|
|
524
522
|
const DEFAULT_C = 36;
|
|
525
523
|
|
|
526
524
|
const updateHooks = {
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
525
|
+
resetState: ( ...args ) => {
|
|
526
|
+
console.log( 'resetting state with >>>> ', JSON.stringify( args ) );
|
|
527
|
+
return true;
|
|
528
|
+
},
|
|
529
|
+
setState: ( ...args ) => {
|
|
530
|
+
console.log( 'merging following into state >>>> ', JSON.stringify( args ) );
|
|
531
|
+
return true;
|
|
532
|
+
}
|
|
535
533
|
};
|
|
536
534
|
|
|
537
535
|
const storageStub = {
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
536
|
+
clone( data ) { return your_clone_function( data ) },
|
|
537
|
+
data: null,
|
|
538
|
+
getItem( key ) { return this.data },
|
|
539
|
+
removeItem( key ) { this.data = null },
|
|
540
|
+
setItem( key, data ) { this.data = data }
|
|
543
541
|
};
|
|
544
542
|
|
|
545
543
|
const Provider = ({ c = DEFAULT_C }) => {
|
|
546
544
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
545
|
+
const [ state, setState ] = useState(() => ({
|
|
546
|
+
a: { b: { c, x: { y: { z: [ 2022 ] } } } }
|
|
547
|
+
}));
|
|
548
|
+
|
|
549
|
+
useEffect(() => {
|
|
550
|
+
// similar to `store.setState`, use the following to update
|
|
551
|
+
// only the changed slice of the context internal state.
|
|
552
|
+
setState({ a: { b: { c } } });
|
|
553
|
+
// Do not do the following: it will override the context internal state.
|
|
554
|
+
// setState({ ...state, a: { ...state.a, b: { ...state.a.b, c } } });
|
|
555
|
+
}, [ c ]);
|
|
556
|
+
|
|
557
|
+
return (
|
|
558
|
+
<ObservableContext.Provider
|
|
559
|
+
prehooks={ updateHooks }
|
|
560
|
+
storage={ storageStub }
|
|
561
|
+
value={ state }
|
|
562
|
+
>
|
|
563
|
+
<Ui />
|
|
564
|
+
</ObservableContext.Provider>
|
|
565
|
+
);
|
|
568
566
|
};
|
|
569
567
|
Provider.displayName = 'Provider';
|
|
570
568
|
|
|
@@ -572,6 +570,7 @@ export default Provider;
|
|
|
572
570
|
```
|
|
573
571
|
|
|
574
572
|
<i><b><u>index.js</u></b></i>
|
|
573
|
+
|
|
575
574
|
```jsx
|
|
576
575
|
import React from 'react';
|
|
577
576
|
import ReactDOM from 'react-dom';
|
|
@@ -584,7 +583,7 @@ ReactDOM.render( <Provider />, document.getElementById( 'root' ) );
|
|
|
584
583
|
<b>v4.1.0</b>
|
|
585
584
|
<table>
|
|
586
585
|
<tbody>
|
|
587
|
-
<tr><td><b>1.</b></td><td>Added new setState
|
|
586
|
+
<tr><td><b>1.</b></td><td>Added new setState <a href="#setstate-tags">tags</a> to facilitate state update operations.</td></tr>
|
|
588
587
|
</tbody>
|
|
589
588
|
</table>
|
|
590
589
|
<hr />
|
package/package.json
CHANGED