react-global-state-hooks 1.0.15 → 1.0.18

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 +390 -1
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -128,7 +128,7 @@ import { useCountGlobal, sendCount } from './useCountGlobal'
128
128
  const CountDisplayerComponent: React.FC = () => {
129
129
  const [count] = useCountGlobal();
130
130
 
131
- return (<Text>{count}<Text/>);
131
+ return (<label>{count}<label/>);
132
132
  }
133
133
 
134
134
  // here we have a separate component that is gonna handle the state of the previous component we created,
@@ -301,3 +301,392 @@ const store = new GlobalStore(0, {
301
301
  ...
302
302
 
303
303
  ...
304
+
305
+ # Examples and Comparison:
306
+
307
+ ## 1. Lets try to share some state between components
308
+
309
+ ### **With the GlobalStore approach, it will look like this:**
310
+
311
+ ```tsx
312
+ type TUser = {
313
+ name: string;
314
+ email: string;
315
+ };
316
+
317
+ const useUserStore = new GlobalStore<TUser>({
318
+ name: null,
319
+ email: null,
320
+ }).getHook();
321
+
322
+ const Component = () => {
323
+ const [currentUser] = useUserStore();
324
+
325
+ return <Text>{currentUser.name}</Text>;
326
+ };
327
+ ```
328
+
329
+ ## Simple, right?
330
+
331
+ ### Let's now see how this same thing would look like by using context:
332
+
333
+ ```tsx
334
+ type TUser = {
335
+ name: string;
336
+ email: string;
337
+ };
338
+
339
+ const UserContext = createContext<{
340
+ currentUser: TUser;
341
+ }>({
342
+ currentUser: null,
343
+ });
344
+
345
+ const UserProvider: React.FC<PropsWithChildren> = ({ children }) => {
346
+ const [currentUser, setCurrentUser] = useState<TUser>(null);
347
+
348
+ // ...get current user information
349
+
350
+ return (
351
+ <UserContext.Provider value={{ currentUser }}>
352
+ {children}
353
+ </UserContext.Provider>
354
+ );
355
+ };
356
+
357
+ const Component = () => {
358
+ const { currentUser } = useContext(UserContext);
359
+
360
+ return <Text>{currentUser.name}</Text>;
361
+ };
362
+
363
+ const App = () => {
364
+ return (
365
+ <UserProvider>
366
+ <Component />
367
+ </UserProvider>
368
+ );
369
+ };
370
+ ```
371
+
372
+ ### We already are able to notice a couple of extra lines right?
373
+
374
+ Let's now add another simple store to the equation
375
+
376
+ ### **With the GlobalStore approach, it will look like this:**
377
+
378
+ ```tsx
379
+ type TUser = {
380
+ name: string;
381
+ email: string;
382
+ };
383
+
384
+ const useUserStore = new GlobalStore<TUser>({
385
+ name: null,
386
+ email: null,
387
+ }).getHook();
388
+
389
+ // we create the store
390
+ const useCountStore = new GlobalStore(0).getHook();
391
+
392
+ const Component = () => {
393
+ const [currentUser] = useUserStore();
394
+
395
+ // from the component we consume the new store
396
+ const [count, setCount] = useCountStore();
397
+
398
+ return <label>{currentUser.name}</label>;
399
+ };
400
+ ```
401
+
402
+ With context, we'll have again to create all the boilerplate, and wrap the component into the new provider...
403
+
404
+ ### **Lets see that**
405
+
406
+ ```tsx
407
+ type TUser = {
408
+ name: string;
409
+ email: string;
410
+ };
411
+
412
+ const UserContext = createContext<{
413
+ currentUser: TUser;
414
+ }>({
415
+ currentUser: null,
416
+ });
417
+
418
+ // let's create the context
419
+ const CountContext = createContext({
420
+ count: 0,
421
+ setCount: (() => {
422
+ throw new Error('not implemented');
423
+ }) as Dispatch<SetStateAction<number>>,
424
+ });
425
+
426
+ const UserProvider: React.FC<PropsWithChildren> = ({ children }) => {
427
+ const [currentUser, setCurrentUser] = useState<TUser>(null);
428
+
429
+ // ...
430
+
431
+ return (
432
+ <UserContext.Provider value={{ currentUser }}>
433
+ {children}
434
+ </UserContext.Provider>
435
+ );
436
+ };
437
+
438
+ // we also need another provider
439
+ const CountProvider: React.FC<PropsWithChildren> = ({ children }) => {
440
+ const [count, setCount] = useState(0);
441
+
442
+ return (
443
+ <CountContext.Provider value={{ count, setCount }}>
444
+ {children}
445
+ </CountContext.Provider>
446
+ );
447
+ };
448
+
449
+ // we need to wrap the component into the new provider (this is for each future context)
450
+ const App = () => {
451
+ return (
452
+ <UserProvider>
453
+ <CountProvider>
454
+ <Component />
455
+ </CountProvider>
456
+ </UserProvider>
457
+ );
458
+ };
459
+
460
+ const Component = () => {
461
+ const { currentUser } = useContext(UserContext);
462
+
463
+ // finally we are able to get access to the new context...
464
+ const { count, setCount } = useContext(CountContext);
465
+
466
+ return <label>{currentUser.name}</label>;
467
+ };
468
+ ```
469
+
470
+ In this example, we are able to see how every time along with creating a good amount of repetitive code, we also have to wrap the necessary components into the Provider... Also, notice how every time we need to modify the **App** component, even when the App component is not gonna use the new state.
471
+
472
+ ### Let's make this a little more complex, now I want to implement custom methods for manipulating the count state, I also want to have the ability to modify the count state **without** having to be subscribed to the changes of the state... have you ever done that?
473
+
474
+ This is a common scenery, and guess what? in the **context** examples, we'll have to create another context, another provider, wrap and everything again...
475
+
476
+ ## Let's see this time first the **context** approach
477
+
478
+ ```tsx
479
+ type TUser = {
480
+ name: string;
481
+ email: string;
482
+ };
483
+
484
+ const UserContext = createContext<{
485
+ currentUser: TUser;
486
+ }>({
487
+ currentUser: null,
488
+ });
489
+
490
+ // let's remove the setter from this context
491
+ const CountContext = createContext({
492
+ count: 0,
493
+ });
494
+
495
+ // lets create another context to share the actions
496
+ const CountContextSetter = createContext({
497
+ increase: (): void => {
498
+ throw new Error('increase is not implemented');
499
+ },
500
+ decrease: (): void => {
501
+ throw new Error('decrease is not implemented');
502
+ },
503
+ });
504
+
505
+ const UserProvider: React.FC<PropsWithChildren> = ({ children }) => {
506
+ const [currentUser, setCurrentUser] = useState<TUser>(null);
507
+
508
+ // ...
509
+
510
+ return (
511
+ <UserContext.Provider value={{ currentUser }}>
512
+ {children}
513
+ </UserContext.Provider>
514
+ );
515
+ };
516
+
517
+ // To don't overcomplicate the example let's just add but providers into this component, that will be enough
518
+ const CountProvider: React.FC<PropsWithChildren> = ({ children }) => {
519
+ const [count, setCount] = useState(0);
520
+
521
+ const increase = () => setCount(count + 1);
522
+ const decrease = () => setCount(count - 1);
523
+
524
+ return (
525
+ //one context is gonna share the edition of the state
526
+ <CountContext.Provider value={{ count }}>
527
+ {/* this second component will share the mutations of the state */}
528
+ <CountContextSetter.Provider value={{ increase, decrease }}>
529
+ {children}
530
+ </CountContextSetter.Provider>
531
+ </CountContext.Provider>
532
+ );
533
+ };
534
+
535
+ // Since we used the same provider we don't need to modify the **App** component, but we do are **Wrapping** everything into one more **Provider**
536
+ const App = () => {
537
+ return (
538
+ <UserProvider>
539
+ <CountProvider>
540
+ {/* lets create two componets instead of one */}
541
+ <ComponentSetter />
542
+ <Component />
543
+ </CountProvider>
544
+ </UserProvider>
545
+ );
546
+ };
547
+
548
+ const ComponentSetter = () => {
549
+ const { increase, decrease } = useContext(CountContextSetter);
550
+
551
+ return (
552
+ <>
553
+ <button onPress={increase}>Increase</button>
554
+ <button onPress={decrease}>Decrease</button>
555
+ </>
556
+ );
557
+ };
558
+
559
+ const Component = () => {
560
+ const { currentUser } = useContext(UserContext);
561
+
562
+ // finally we are able to get access to the new context...
563
+ const { count } = useContext(CountContext);
564
+
565
+ return (
566
+ <>
567
+ <label>{currentUser.name}</label>
568
+ <label>{count}</label>
569
+ </>
570
+ );
571
+ };
572
+ ```
573
+
574
+ Wow, a lot!!! just to be able to separate the mutations... and have mutations!!
575
+
576
+ ### it would be easier with the GlobalStore? Let's see.
577
+
578
+ ```tsx
579
+ type TUser = {
580
+ name: string;
581
+ email: string;
582
+ };
583
+
584
+ const useUser = new GlobalStore<TUser>({
585
+ name: null,
586
+ email: null,
587
+ }).getHook();
588
+
589
+ // let's modify the store to add custom actions, the second parameter is configuration let's just pass null for now
590
+ const countStore = new GlobalStore(0, null, {
591
+ increase() {
592
+ return ({ setState }: StoreTools<number>) => {
593
+ setState((state) => state + 1);
594
+ };
595
+ },
596
+
597
+ decrease() {
598
+ return ({ setState }: StoreTools<number>) => {
599
+ setState((state) => state - 1);
600
+ };
601
+ },
602
+ } as const);
603
+
604
+ const useCount = countStore.getHook();
605
+
606
+ // this actions don't use hooks, but are connected to the store and all the subscribers will be notified
607
+ const [, countActions] = countStore.getHookDecoupled();
608
+
609
+ // this component is not subscribed to the store, so it will not be notified when the state changes
610
+ const ComponentSetter = () => {
611
+ return (
612
+ <>
613
+ <button onPress={countActions.increase}>Increase</button>
614
+ <button onPress={countActions.decrease}>Decrease</button>
615
+ </>
616
+ );
617
+ };
618
+
619
+ // this component is subscribed to the store, so it will be notified when the state changes
620
+ const Component = () => {
621
+ const [user] = useUser();
622
+ const [count, actions] = useCount();
623
+
624
+ return (
625
+ <>
626
+ <label>{count}</label>
627
+ </>
628
+ );
629
+ };
630
+ ```
631
+
632
+ ### So let's analyze what happened
633
+
634
+ To restrict the state manipulations with the custom actions, we just need to add a third parameter to the store.
635
+
636
+ ```ts
637
+ const countStore = new GlobalStore(0, null, {
638
+ log: (action: string) => () => console.log(action),
639
+
640
+ // every action is a function that returns a function that receives the store tools
641
+ increase() {
642
+ return ({ setState, getState }: StoreTools<number>): number => {
643
+ setState((state) => state + 1);
644
+
645
+ // actions are able to communicate between them
646
+ this.log('increase');
647
+
648
+ return getState();
649
+ };
650
+ },
651
+ } as const);
652
+
653
+ // the const is necessary to avoid typescript errors
654
+ ```
655
+
656
+ All the library is strongly typed, we use generics to return the correct data type in each action.
657
+
658
+ ```ts
659
+ const [, actions] = countStore.getHookDecoupled();
660
+
661
+ // for example the type of actions.increase will be: () => number
662
+ // just in case, even the parameters of the actions are gonna be exposed through TS
663
+ ```
664
+
665
+ ## getHookDecoupled
666
+
667
+ ### **getHookDecoupled** returns a tuple with the state and the actions,
668
+
669
+ This is so useful when you want to use the actions without having to be subscribed to changes of the state.
670
+ There is also a third element in the tuple which is a function for getting the metadata of the store
671
+
672
+ ### the metadata of the store is not reactive information which could be shared through the store
673
+
674
+ ## Adding metadata to the store
675
+
676
+ ```tsx
677
+ const [, , getMetadata] = new GlobalStore(0, {
678
+ metadata: {
679
+ isStoredSyncronized: false,
680
+ },
681
+ }).getHookDecoupled();
682
+
683
+ console.log(getMetadata().isStoredSyncronized); // false
684
+ ```
685
+
686
+ The setMetadata is part of the store tools, so it can be used in the actions, but againg the metadata is not reactive!! so it will not trigger a re-render on the subscribers
687
+
688
+ ...
689
+
690
+ ...
691
+
692
+ # That's it for now!! hope you enjoy coding!!
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-global-state-hooks",
3
- "version": "1.0.15",
3
+ "version": "1.0.18",
4
4
  "description": "This is a package to easily handling global-state across your react components No-redux, No-context.",
5
5
  "main": "lib/GlobalStore.js",
6
6
  "files": [
@@ -60,6 +60,6 @@
60
60
  "react-dom": "workspace:*"
61
61
  },
62
62
  "dependencies": {
63
- "react-native-global-state-hooks": "^2.1.9"
63
+ "react-native-global-state-hooks": "^2.1.10"
64
64
  }
65
65
  }