1.0.0-alpha.58 • Published 8 months ago

@neurongsm/react v1.0.0-alpha.58

Weekly downloads
-
License
MIT
Repository
github
Last release
8 months ago

NeuronGSM React

Neuron Global State Manager for React.js. This is a React.js specific global state management library that uses NeuronGSM Core internally to manage state. It is fast, small, and does not need React Context to manage state. It uses a declarative approach for instantiating stores and uses hooks to manage those stores.

Manage Global State

  1. Create a new Store
import NeuronGSM from '@neurongsm/react';

export const {State, useNeuron} = NeuronGSM.Store();

export default function AppStore(){


    return(
        <>
            <State
                name={'fruit'}
                state={'apple'}
            />

            <State
                name={'car'}
                state={'Tesla'}
            />
        </>
    )    
}
  1. Instantiate Store
function App(){

    return(
        <>
            <AppStore/>
            <Comp/>
        </>
    );
}
  1. Get and Set state with Store hook
function Comp(){

    const [fruit, setFruit] = useNeuron('fruit');
    const [car, setCar] = useNeuron('car');

    return(
        <p>This is my favorite fruit, {fruit}</p>
        <p>This is my favorite car, {car}</p>
        <button onClick={() => setFruit('orange')}>Change Fruit</button>
        <button onClick={() => setCar('Ford')}>Change Car</button>
    );
}

Alternatively to the magic string selector like 'fruit'. You can also select state with an arrow function like this (store) => store.fruit.

function Comp(){

    const [fruit, setFruit] = useNeuron((store) => store.fruit);
    const [car, setCar] = useNeuron((store) => store.car);
}

Slices

Slices allow deep nested objects to be retrieved and updated easily, with the standard NeuronGSM getter and setter api.

Below we have a Store item that has a deep nested object passed to it.

<State
    name={'person'}
    state={{
        name: 'Bob',
        meta: {
            age: 30,
            job: {
                title: 'Developer'.
                salary: 90,000
            }
        }
    }}
/>

We want to be able to retrieve certain properties and set those properties with out complicated object spreading. We can use slices to do this. Example below:

function Comp(){

    const [name, setName] = useNeuron((store) => store.person.name);
    const [title, setTitle] = useNeuron((store) => store.person.meta.job.title);
    const [salary, setSalary] = useNeuron((store) => store.person.meta.job.salary);

    return(
        <p>My name is {name}</p>
        <p>I am a {title}</p>
        <p>I make {salary} a year.</p>
        <button onClick={() => setName('Jim')}>Change Name</button>
        <button onClick={() => setTitle('Designer')}>Change Title</button>
        <button onClick={() => setSalary(60000)}>Change Salary</button>
    );
}

Actions

Actions are custom dedicated methods to manipulate state in the store. They target the state that they are passed to.

The action prop on the State component takes a function that returns an object. The object properties are the state methods used to manipulate store state.

The function exposes a dispatch method that allows you to manipulate the payload within the action method. Payload state and data methods can be updated mutably. Example below.

<State
    name={'count'}
    state={0}
    actions={(dispatch) => ({
        increment: () => {
            dispatch((payload) => {
                const current = payload.prevState;
                payload.state = current + 1;
            });
        },
        decrement: () => {
            dispatch((payload) => {
                const current = payload.prevState;
                payload.state = current - 1;
            });
        }
    })}
/>

The useNeuron hook returns a third parameter that gives you access to the action methods in the component it is called in. Example Below.

function Comp(){

    const [count, setCount, { increment, decrement }] = useNeuron('count');

    return(
        <p>count: {count}</p>

        <button onClick={() => increment()}>Increment</button>
        <button onClick={() => decrement()}>decrement</button>
        <button onClick={() => setCount(100)}>100</button>
    );
}

Middleware

Middleware is logic that runs at different times during the store dispatch process. This allows for state to be manipulated, interrigated, logged, and even cancelled during a dispatch. Middleware is set on a store item. Any time the store item gets a dispatch, the appropriate middleware will run. And example middleware is below:

<State
    name={'fruit'}
    state={'apple'}
    onRun={(payload) => {
        console.log('The dispatched state is: ', payload.state);
    }}
/>

Types

All three types of middleware have access to the payload object. This object has properties and methods that allow the middleware to interogate, manipulate, or cancel the dispatch. You may use all three types on one store item.

OnLoad

This only fires once as the store is instantiated. It will not run again, even if a dispatch happens.

<State
    name={'fruit'}
    state={'apple'}
    onLoad={(payload) => {
        console.log('I fire only once when the store first instantiates');
    }}
/>

OnRun

This fires every time a dispatch is sent. When this middleware resolves, the dispatch will also resolve and the store will be updated.

<State
    name={'fruit'}
    state={'apple'}
    onRun={(payload) => {
        if(payload.state === 'lemon'){
            console.log('Gross, I hate lemons!')
            payload.cancelDispatch();
        }else{
            console.log('I love ', payload.state);
        }
    }}
/>

OnCallback

This fires only when all other middleware and the dispatch resolves. This will fire even if a dispatch is cancelled.

<State
    name={'fruit'}
    state={'apple'}
    onCallback={(payload) => {
        console.log('The store has been updated....');
    }}
/>

Payload

The payload object is used by middleware to manipulate the dispatch process. Below is the list of methods and properties that are available in each payload.

  • key - This is the name of the store item the dispatch is targeting.
  • prevState - Previous state.
  • state - A writable property that will be the next state.
  • data - A writable property that can be used by useDispatch to send non state data to store middleware.
  • features - Features set for the store item. (examples: onLoad, onRun, onCallback, and module specific props passed to the State component)
  • cancelDispatch - Method that will cancel the dispatch (nothing will be saved to store).
  • isDispatchCancelled - Method that can be used in onCallback middleware to determine if dispatch was cancelled.
  • get - Method that gets state from a store item by key.
  • set - Method that sets state of a store item by key.
  • reset - Method that resets store item to it's initial state by key. Note: If no key is passed then it will reset all store items to initial. state.

Modules

Modules are a way to hook into store middleware and extend NeuronGSM with features like state persistance and dev tools. Below is an example of extending a NeuronGSM store with state persistence by using the Persist module. You can use the Store.Use component to inject a module into your store. Each module works different and might have a different api. In the case below, the Persist module is instantiated and the feature flag persist is set on the store items that you want to run the module on.

import NeuronGSM from '@neurongsm/react';
import Persist from '@neurongsm/persist';

export const {State, Module, useNeuron} = NeuronGSM.Store();

export default function AppStore(){


    return(
        <>
            <Module use={Persist}/>

            <State
                name={'fruit'}
                state={'apple'}
                persist//This tells the module to run on this store item
            />

            <State
                name={'car'}
                state={'Tesla'}
            />
        </>
    )    
}

~ Modules run before custom middleware. ~ Modules must be instantiated before store items.

Private Stores

By default NeuronGSM stores are globally instantiated. This means that any component in the component tree has access to it, via store selectors. This also means that stores are not tied to any one component and its children. Private stores can be setup so only components nested as children in the Private store provider has access to that store. This allows us to prevent components that render outside that scope from affecting the store. It also allows for stores to be tide to a component which means you can create one component with a dedicated store that can be reused as seperate instances.

Create Private Store

import NeuronGSM from '@neurongsm/react';
import Persist from '@neurongsm/persist';

// Private store must be instantiated outside of Store component;
export const {usePrivateStore, Private} = NeuronGSM.PrivateStore();

export default function AppStore({children}){

    // Private store hook is ran inside of Store component
    const {Module, State} = usePrivateStore();

    return(
        <>
            <Module use={Persist}/>

            <State
                name={'fruit'}
                state={'apple'}
            />

            <State
                name={'car'}
                state={'Tesla'}
            />

            {/** Private provider componet is set with children under Module and State JSX**/}
            <Private>
                {children}
            </Private>
        </>
    )    
}

Instantiate Private Store

The AppStore can now be instantiated in a JSX file somewhere.

import AppStore from './';
import SomeChildComp from './SomeChildComp';

export default function App(){

    return(
        <>
            <AppStore>
                <SomeChildComp>
            </AppStore>
        </>
    )    
}

Get and Set State

You can get and set state in children components just like a regular store.

import {useNeuron} from './';

export default function SomeChildComp(){

    const [fruit, setFruit] = useNeuron('fruit');
    const [car, setCar] = useNeuron('car');

    return(
        <>
            <p>This is my favorite fruit, {fruit}</p>
            <p>This is my favorite car, {car}</p>
            <button onClick={() => setFruit('orange')}>Change Fruit</button>
            <button onClick={() => setCar('Ford')}>Change Car</button>
        </>
    )    
}

~ The Private setter/getter hooks MUST be called within the Store scope or it will throw an error.

1.0.0-alpha.58

8 months ago

1.0.0-alpha.57

8 months ago

1.0.0-alpha.56

8 months ago

1.0.0-alpha.55

8 months ago

1.0.0-alpha.54

8 months ago

1.0.0-alpha.53

8 months ago

1.0.0-alpha.52

8 months ago

1.0.0-alpha.51

9 months ago

1.0.0-alpha.50

9 months ago

1.0.0-alpha.49

9 months ago

1.0.0-alpha.47

9 months ago

1.0.0-alpha.46

9 months ago

1.0.0-alpha.45

9 months ago

1.0.0-alpha.44

9 months ago

1.0.0-alpha.43

9 months ago

1.0.0-alpha.42

9 months ago

1.0.0-alpha.41

9 months ago

1.0.0-alpha.40

9 months ago

1.0.0-alpha.39

9 months ago

1.0.0-alpha.38

9 months ago

1.0.0-alpha.37

9 months ago

1.0.0-alpha.36

9 months ago

1.0.0-alpha.34

9 months ago

1.0.0-alpha.33

9 months ago

1.0.0-alpha.32

9 months ago

1.0.0-alpha.31

9 months ago

1.0.0-alpha.30

9 months ago

1.0.0-alpha.29

9 months ago

1.0.0-alpha.28

9 months ago

1.0.0-alpha.27

9 months ago

1.0.0-alpha.26

9 months ago

1.0.0-alpha.25

9 months ago

1.0.0-alpha.24

9 months ago

1.0.0-alpha.23

9 months ago

1.0.0-alpha.22

9 months ago

1.0.0-alpha.21

9 months ago

1.0.0-alpha.20

9 months ago

1.0.0-alpha.19

9 months ago

1.0.0-alpha.18

9 months ago

1.0.0-alpha.17

9 months ago