@webkrafters/react-observable-context 4.1.0-rc.2 → 4.1.0-rc.3
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 +113 -77
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,6 +41,43 @@ npm install --save @webkrafters/react-observable-context
|
|
|
41
41
|
|
|
42
42
|
May also see <b><a href="#changes">What's Changed?</a></b> section below.
|
|
43
43
|
|
|
44
|
+
<h1 id="toc">Table of Contents</h1>
|
|
45
|
+
|
|
46
|
+
<a href="#intro">Intro</a><br />
|
|
47
|
+
<a href="#concepts">Concepts</a><br />
|
|
48
|
+
<a href="#client">Client</a><br />
|
|
49
|
+
<a href="#prehooks">Prehooks</a><br />
|
|
50
|
+
<a href="#property-path">Property Path</a><br />
|
|
51
|
+
<a href="#fullstate-selectorkey">@@STATE</a><br />
|
|
52
|
+
<a href="#provider">Provider</a><br />
|
|
53
|
+
<a href="#selector-map">Selector Map</a><br />
|
|
54
|
+
<a href="#storage">Storage</a><br />
|
|
55
|
+
<a href="#store">Store</a><br />
|
|
56
|
+
<a href="#store-resetstate">Reset State</a><br />
|
|
57
|
+
<a href="#store-setstate">Set State</a><br />
|
|
58
|
+
<a href="#indexing">Array Indexing</a><br />
|
|
59
|
+
<a href="#setstate-tags">Using Tag Commands</a><br />
|
|
60
|
+
<a href="#clear-tag-usage">@@CLEAR Usage Example</a><br />
|
|
61
|
+
<a href="#delete-tag-usage">@@DELETE Usage Example</a><br />
|
|
62
|
+
<a href="#move-tag-usage">@@MOVE Usage Example</a><br />
|
|
63
|
+
<a href="#push-tag-usage">@@PUSH Usage Example</a><br />
|
|
64
|
+
<a href="#replace-tag-usage">@@REPLACE Usage Example</a><br />
|
|
65
|
+
<a href="#set-tag-usage">@@SET Usage Example</a><br />
|
|
66
|
+
<a href="#splice-tag-usage">@@SPLICE Usage Example</a><br />
|
|
67
|
+
<a href="#set-state-with-tags">Combination Usage Example</a><br />
|
|
68
|
+
<a href="#api">API</a><br />
|
|
69
|
+
<a href="#connect">Connect HoC</a><br />
|
|
70
|
+
<a href="#create-context">CreateContext Function</a><br />
|
|
71
|
+
<a href="#usage-error">UsageError Exception</a><br />
|
|
72
|
+
<a href="#usecontext">UseContext Hook</a><br />
|
|
73
|
+
<a href="#usage">Usage</a><br />
|
|
74
|
+
<a href="#create-context-usage">Creating context</a><br />
|
|
75
|
+
<a href="#provider-usage">Setting up the Provider</a><br />
|
|
76
|
+
<a href="#connect-usage">Consuming context (hoc method)</a><br />
|
|
77
|
+
<a href="#usecontext-usage">Consuming context (hook with memo method)</a><br />
|
|
78
|
+
<a href="#changes">What's Changed?</a><br />
|
|
79
|
+
<a href="#license">License</a><br />
|
|
80
|
+
|
|
44
81
|
# Intro
|
|
45
82
|
|
|
46
83
|
A context bearing an observable consumer [store](#store). State changes within the store's internal state are only broadcasted to components subscribed to the store (the [clients](#client)). In this way, the `React-Observable-Context` prevents repeated automatic re-renderings of entire component trees resulting from ***context*** state changes.
|
|
@@ -215,7 +252,7 @@ To overwrite current state slices with new values, <b>7</b> tag commands have be
|
|
|
215
252
|
</ol>
|
|
216
253
|
<b>Examples:</b><br /><br />
|
|
217
254
|
|
|
218
|
-
<i><b>@@CLEAR:</b> (takes no arguments)</i>
|
|
255
|
+
<i id="clear-tag-usage"><b>@@CLEAR:</b> (takes no arguments)</i>
|
|
219
256
|
|
|
220
257
|
```jsx
|
|
221
258
|
const state = {
|
|
@@ -242,7 +279,7 @@ store.setState({ a: { b: [ '@@CLEAR', state.a.b[1] ] } }) // or store.setState({
|
|
|
242
279
|
store.setState({ a: { b: { 0: '@@CLEAR' } } }) // or store.setState({ a: { b: { 0: { '@@CLEAR': <anything> } } } })
|
|
243
280
|
```
|
|
244
281
|
|
|
245
|
-
<i><b>@@DELETE:</b> (takes an array argument listing property keys to delete)</i>
|
|
282
|
+
<i id="delete-tag-usage"><b>@@DELETE:</b> (takes an array argument listing property keys to delete)</i>
|
|
246
283
|
|
|
247
284
|
```jsx
|
|
248
285
|
const state = {
|
|
@@ -264,7 +301,7 @@ store.setState({ a: { b: [ state.a.b[ 0 ], { '@@DELETE': [ 'x', 'z' ] } ] } })
|
|
|
264
301
|
store.setState({ a: { b: { 1: { '@@DELETE': [ 'x', 'z' ] } } } })
|
|
265
302
|
```
|
|
266
303
|
|
|
267
|
-
<i><b>@@MOVE:</b> (takes an array argument listing: -/+fromIndex, -/+toIndex and optional +numItems?. numItems = 1 by default)</i>
|
|
304
|
+
<i id="move-tag-usage"><b>@@MOVE:</b> (takes an array argument listing: -/+fromIndex, -/+toIndex and optional +numItems?. numItems = 1 by default)</i>
|
|
268
305
|
|
|
269
306
|
```jsx
|
|
270
307
|
const state = {
|
|
@@ -282,7 +319,7 @@ store.setState({ a: { b: { '@@MOVE': [ 0, 1 ] } } }) // or store.setState({ a: {
|
|
|
282
319
|
store.setState({ a: { q: { '@@MOVE': [ 4, 1, 4 ] } } }) // or store.setState({ a: { q: { '@@MOVE': [ -5, -8, 4 ] } } })
|
|
283
320
|
```
|
|
284
321
|
|
|
285
|
-
<i><b>@@PUSH:</b> (takes an array argument listing new values to append)</i>
|
|
322
|
+
<i id="push-tag-usage"><b>@@PUSH:</b> (takes an array argument listing new values to append)</i>
|
|
286
323
|
|
|
287
324
|
```jsx
|
|
288
325
|
const state = {
|
|
@@ -296,7 +333,7 @@ store.setState({ a: { '@@PUSH': [{ n: 5 }] } }) // assigning a '@@PUSH' command
|
|
|
296
333
|
store.setState({ a: { b: { '@@PUSH': [{ x: 27, y: 28, z: 29 }, { x: 37, y: 38, z: 39 }] } } })
|
|
297
334
|
```
|
|
298
335
|
|
|
299
|
-
<i><b>@@REPLACE:</b> (takes an argument holding the replacment value)</i>
|
|
336
|
+
<i id="replace-tag-usage"><b>@@REPLACE:</b> (takes an argument holding the replacment value)</i>
|
|
300
337
|
|
|
301
338
|
```jsx
|
|
302
339
|
const state = {
|
|
@@ -315,7 +352,7 @@ store.setState({ a: { b: [ state.a.b[ 0 ], { '@@REPLACE': { x: 97, y: 98, z: 99
|
|
|
315
352
|
store.setState({ a: { b: { 1: { '@@REPLACE': { x: 97, y: 98, z: 99 } } } } })
|
|
316
353
|
```
|
|
317
354
|
|
|
318
|
-
<i><b>@@SET:</b> (takes an argument holding either the replacment value or a compute function returning the replacement value)</i>
|
|
355
|
+
<i id="set-tag-usage"><b>@@SET:</b> (takes an argument holding either the replacment value or a compute function returning the replacement value)</i>
|
|
319
356
|
|
|
320
357
|
```jsx
|
|
321
358
|
/*
|
|
@@ -342,7 +379,7 @@ store.setState({ a: { b: [ state.a.b[ 0 ], { '@@SET': currentValue => ({ ...curr
|
|
|
342
379
|
store.setState({ a: { b: { 1: { '@@SET': currentValue => ({ ...currentValue, x: 97, y: 98, z: 99 }) } } } })
|
|
343
380
|
```
|
|
344
381
|
|
|
345
|
-
<i><b>@@SPLICE:</b> (takes an array argument listing: -/+fromIndex, +deleteCount and optional ...newItems? newItems = ...[] by default)</i>
|
|
382
|
+
<i id="splice-tag-usage"><b>@@SPLICE:</b> (takes an array argument listing: -/+fromIndex, +deleteCount and optional ...newItems? newItems = ...[] by default)</i>
|
|
346
383
|
|
|
347
384
|
```jsx
|
|
348
385
|
const state = {
|
|
@@ -360,7 +397,7 @@ store.setState({ a: { b: { '@@SPLICE': [ 0, 1 ] } } }) // or store.setState({ a:
|
|
|
360
397
|
store.setState({ a: { q: { '@@SPLICE': [ 4, 4, 33, 88 ] } } }) // or store.setState({ a: { q: { '@@SPLICE': [ -5, 4, 33, 88 ] } } })
|
|
361
398
|
```
|
|
362
399
|
|
|
363
|
-
<h3><b><i>Combination Usage:</i></b></h3>
|
|
400
|
+
<h3 id="set-state-with-tags"><b><i>Combination Usage:</i></b></h3>
|
|
364
401
|
|
|
365
402
|
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.
|
|
366
403
|
|
|
@@ -397,7 +434,7 @@ store.setState({
|
|
|
397
434
|
|
|
398
435
|
# API
|
|
399
436
|
|
|
400
|
-
The React-Observable-Context module
|
|
437
|
+
The React-Observable-Context module exports named constants and the following **4** main entities namely:
|
|
401
438
|
<ol>
|
|
402
439
|
<li style="padding-bottom: 5px">
|
|
403
440
|
<p style="margin: 0 0 5px 5px">
|
|
@@ -415,12 +452,12 @@ The React-Observable-Context module contains **4** exports namely:
|
|
|
415
452
|
</li>
|
|
416
453
|
<li style="padding-bottom: 5px">
|
|
417
454
|
<p style="margin: 0 0 5px 5px">
|
|
418
|
-
<b>createContext</b> is a zero-parameter function returning a <code>React-Observable-Context</code> object. This object is the store-bearing context. To access the context's <a href="#store">store</a>, pass the context as a <code>context</code> parameter to either the <a href="#connect">connect</a> function or the <a href="#usecontext">useContext</a> hook.
|
|
455
|
+
<b id="create-context">createContext</b> is a zero-parameter function returning a <code>React-Observable-Context</code> object. This object is the store-bearing context. To access the context's <a href="#store">store</a>, pass the context as a <code>context</code> parameter to either the <a href="#connect">connect</a> function or the <a href="#usecontext">useContext</a> hook.
|
|
419
456
|
</p>
|
|
420
457
|
</li>
|
|
421
458
|
<li style="padding-bottom: 5px">
|
|
422
459
|
<p style="margin: 0 0 5px 5px">
|
|
423
|
-
<b>UsageError</b> class is the Error type reported for attempts to access this context's store outside of its Provider component tree.
|
|
460
|
+
<b id="usage-error">UsageError</b> class is the Error type reported for attempts to access this context's store outside of its Provider component tree.
|
|
424
461
|
</p>
|
|
425
462
|
</li>
|
|
426
463
|
<li>
|
|
@@ -440,14 +477,74 @@ The React-Observable-Context module contains **4** exports namely:
|
|
|
440
477
|
|
|
441
478
|
# Usage
|
|
442
479
|
|
|
443
|
-
<i><u><b>context.js</b></u></i>
|
|
480
|
+
<i id="create-context-usage"><u><b>context.js</b></u></i>
|
|
444
481
|
|
|
445
482
|
```jsx
|
|
446
483
|
import { createContext } from '@webkrafters/react-observable-context';
|
|
447
484
|
export default createContext();
|
|
448
485
|
```
|
|
449
486
|
|
|
450
|
-
<i><u
|
|
487
|
+
<i id="provider-usage"><b><u>provider.js</u></b></i>
|
|
488
|
+
|
|
489
|
+
```jsx
|
|
490
|
+
import React, { useEffect, useState } from 'react';
|
|
491
|
+
import ObservableContext from './context';
|
|
492
|
+
import Ui from './ui';
|
|
493
|
+
|
|
494
|
+
const DEFAULT_C = 36;
|
|
495
|
+
|
|
496
|
+
const updateHooks = {
|
|
497
|
+
resetState: ( ...args ) => {
|
|
498
|
+
console.log( 'resetting state with >>>> ', JSON.stringify( args ) );
|
|
499
|
+
return true;
|
|
500
|
+
},
|
|
501
|
+
setState: ( ...args ) => {
|
|
502
|
+
console.log( 'merging following into state >>>> ', JSON.stringify( args ) );
|
|
503
|
+
return true;
|
|
504
|
+
}
|
|
505
|
+
};
|
|
506
|
+
|
|
507
|
+
const storageStub = {
|
|
508
|
+
clone( data ) { return your_clone_function( data ) },
|
|
509
|
+
data: null,
|
|
510
|
+
getItem( key ) { return this.data },
|
|
511
|
+
removeItem( key ) { this.data = null },
|
|
512
|
+
setItem( key, data ) { this.data = data }
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
const Provider = ({ c = DEFAULT_C }) => {
|
|
516
|
+
|
|
517
|
+
const storeRef = useRef();
|
|
518
|
+
|
|
519
|
+
const [ state, setState ] = useState(() => ({
|
|
520
|
+
a: { b: { c, x: { y: { z: [ 2022 ] } } } }
|
|
521
|
+
}));
|
|
522
|
+
|
|
523
|
+
useEffect(() => {
|
|
524
|
+
// similar to `store.setState`, use the following to update
|
|
525
|
+
// only the changed slice of the context internal state.
|
|
526
|
+
setState({ a: { b: { c } } });
|
|
527
|
+
// Do not do the following: it will override the context internal state.
|
|
528
|
+
// setState({ ...state, a: { ...state.a, b: { ...state.a.b, c } } });
|
|
529
|
+
}, [ c ]);
|
|
530
|
+
|
|
531
|
+
return (
|
|
532
|
+
<ObservableContext.Provider
|
|
533
|
+
prehooks={ updateHooks }
|
|
534
|
+
ref={ storeRef }
|
|
535
|
+
storage={ storageStub }
|
|
536
|
+
value={ state }
|
|
537
|
+
>
|
|
538
|
+
<Ui />
|
|
539
|
+
</ObservableContext.Provider>
|
|
540
|
+
);
|
|
541
|
+
};
|
|
542
|
+
Provider.displayName = 'Provider';
|
|
543
|
+
|
|
544
|
+
export default Provider;
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
<i id="connect-usage"><u><b>ui.js</b></u> (connect method)</i>
|
|
451
548
|
|
|
452
549
|
```jsx
|
|
453
550
|
import React, { useCallback, useEffect } from 'react';
|
|
@@ -479,7 +576,7 @@ const Ui = () => (
|
|
|
479
576
|
export default Ui;
|
|
480
577
|
```
|
|
481
578
|
|
|
482
|
-
<i><u><b>ui.js</b></u> (useContext with memo method)</i>
|
|
579
|
+
<i id="usecontext-usage"><u><b>ui.js</b></u> (useContext with memo method)</i>
|
|
483
580
|
|
|
484
581
|
```jsx
|
|
485
582
|
import React, { memo, useCallback, useEffect } from 'react';
|
|
@@ -514,66 +611,6 @@ const Ui = () => (
|
|
|
514
611
|
export default Ui;
|
|
515
612
|
```
|
|
516
613
|
|
|
517
|
-
<i id="provider-usage"><b><u>provider.js</u></b></i>
|
|
518
|
-
|
|
519
|
-
```jsx
|
|
520
|
-
import React, { useEffect, useState } from 'react';
|
|
521
|
-
import ObservableContext from './context';
|
|
522
|
-
import Ui from './ui';
|
|
523
|
-
|
|
524
|
-
const DEFAULT_C = 36;
|
|
525
|
-
|
|
526
|
-
const updateHooks = {
|
|
527
|
-
resetState: ( ...args ) => {
|
|
528
|
-
console.log( 'resetting state with >>>> ', JSON.stringify( args ) );
|
|
529
|
-
return true;
|
|
530
|
-
},
|
|
531
|
-
setState: ( ...args ) => {
|
|
532
|
-
console.log( 'merging following into state >>>> ', JSON.stringify( args ) );
|
|
533
|
-
return true;
|
|
534
|
-
}
|
|
535
|
-
};
|
|
536
|
-
|
|
537
|
-
const storageStub = {
|
|
538
|
-
clone( data ) { return your_clone_function( data ) },
|
|
539
|
-
data: null,
|
|
540
|
-
getItem( key ) { return this.data },
|
|
541
|
-
removeItem( key ) { this.data = null },
|
|
542
|
-
setItem( key, data ) { this.data = data }
|
|
543
|
-
};
|
|
544
|
-
|
|
545
|
-
const Provider = ({ c = DEFAULT_C }) => {
|
|
546
|
-
|
|
547
|
-
const storeRef = useRef();
|
|
548
|
-
|
|
549
|
-
const [ state, setState ] = useState(() => ({
|
|
550
|
-
a: { b: { c, x: { y: { z: [ 2022 ] } } } }
|
|
551
|
-
}));
|
|
552
|
-
|
|
553
|
-
useEffect(() => {
|
|
554
|
-
// similar to `store.setState`, use the following to update
|
|
555
|
-
// only the changed slice of the context internal state.
|
|
556
|
-
setState({ a: { b: { c } } });
|
|
557
|
-
// Do not do the following: it will override the context internal state.
|
|
558
|
-
// setState({ ...state, a: { ...state.a, b: { ...state.a.b, c } } });
|
|
559
|
-
}, [ c ]);
|
|
560
|
-
|
|
561
|
-
return (
|
|
562
|
-
<ObservableContext.Provider
|
|
563
|
-
prehooks={ updateHooks }
|
|
564
|
-
ref={ storeRef }
|
|
565
|
-
storage={ storageStub }
|
|
566
|
-
value={ state }
|
|
567
|
-
>
|
|
568
|
-
<Ui />
|
|
569
|
-
</ObservableContext.Provider>
|
|
570
|
-
);
|
|
571
|
-
};
|
|
572
|
-
Provider.displayName = 'Provider';
|
|
573
|
-
|
|
574
|
-
export default Provider;
|
|
575
|
-
```
|
|
576
|
-
|
|
577
614
|
<i><b><u>index.js</u></b></i>
|
|
578
615
|
|
|
579
616
|
```jsx
|
|
@@ -590,8 +627,8 @@ ReactDOM.render( <Provider />, document.getElementById( 'root' ) );
|
|
|
590
627
|
<thead><tr><th>v4.1.0</th></tr></thead>
|
|
591
628
|
<tbody>
|
|
592
629
|
<tr><td><b>1.</b></td><td>Added new setState <a href="#setstate-tags">tags</a> to facilitate state update operations.</td></tr>
|
|
593
|
-
<tr><td><b>2.</b></td><td>Exposing the store via its Context Provider
|
|
594
|
-
<tr><td><b>3.</b></td><td>Exporting crucial constants such as
|
|
630
|
+
<tr><td><b>2.</b></td><td>Exposing the store via its Context Provider <code>ref</code> attribute.</td></tr>
|
|
631
|
+
<tr><td><b>3.</b></td><td>Exporting crucial constants such as <b>@@STATE</b> and setState <a href="#setstate-tags">tags</a> such as <b>@@CLEAR</b>, <b>@@MOVE</b> etc.</td></tr>
|
|
595
632
|
</tbody>
|
|
596
633
|
<thead><tr><th>v4.0.0</th></tr></thead>
|
|
597
634
|
<tbody>
|
|
@@ -605,7 +642,6 @@ ReactDOM.render( <Provider />, document.getElementById( 'root' ) );
|
|
|
605
642
|
</tbody>
|
|
606
643
|
</table>
|
|
607
644
|
|
|
608
|
-
|
|
609
645
|
# License
|
|
610
646
|
|
|
611
647
|
MIT
|
package/package.json
CHANGED