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