README
custom-react-store ·
Custom React Store is a light-weight store provider that can be used by react apps for global state managemnent with redux-like features but using purely react components.
Motivation
This Custom React Store was created to be a light-weight alternative to using React-Redux library for medium to light weight app (or create-react-app) need for global state managemnent also with redux-like features and does not use any external libraries. The React app demonstrates a working example on how to use the custom react store. The react store uses the useContext and useReducer react hooks to implement an app state management system. Therefore your react app version should support this hooks as well.
Install
npm install --save custom-react-store
Table of content
Usage
custom-react-store
provides 3 types of store classes.
Custom store
Import the CustomStore
class and initialize the store outside the react component. Wrap the components you wish to provide store to via .Provider
component of the store instance then pass the store data to the .Provider
via the value
prop. Finally, export the CustomStore
instance to be accessible from other component.
// App.jsx
import React from 'react';
import { CustomStore } from 'custom-react-store';
import Counter from './components/Counter/Counter';
// Initialize the store with a name and export the store instance
export const customStore = new CustomStore('Custom Store');
.
// This could be any component
const App = () => {
const [counter, setCounter] = useState(0);
// Wrap the children with the provider property of the store
// Pass the value to be provided globally to the children components to the *value* prop
return (
<customStore.Provider value={{ counter, setCounter }}>
<h3>Custom Store Example</h3>
<Counter />
</customStore.Provider>
);
}
export default App;
Access the store data in the Counter
component. .useStore
method of the store instance returns an object of storeStateObject
// ./components/Counter/Counter.jsx
import React from 'react';
// import the store instance
import { customStore } from '../../App';
const Counter = () => {
// Destruct the store data
const { counter, setCounter } = customStore.useStore();
// Use the store data
return (
<div>
<div>{counter}</div>
<div>
<button onClick={() => setCounter(counter1 - 1)}>-</button>
<button onClick={() => setCounter(0)}>reset</button>
<button onClick={() => setCounter(counter1 + 1)}>+</button>
</div>
</div>
)
}
export default Counter;
CustomStore
can be instantiated as many as needed and in any part of the application.
Custom redux store
Custom redux store provides a redux like interface.
Firstly, we need to setup the store.
// ./store/counterSlice/index.js
// Store data instance
export const initialState = {
counter: 0
}
// Reducer to update the store
export const reducer = (state, action) => {
switch (action.type) {
case 'CHANGE':
return { ...state, counter: state.counter + action.payload }
case 'RESET':
return { ...state, counter: 0 }
default:
return state
}
}
// Actions object
export const actions = {
change: (payload) => ({ type: 'CHANGE', payload }),
reset: { type: 'RESET' }
}
Import the CustomReduxStore
class and initialize the store outside the react component. Wrap the components you wish to provide store to via .Provider
component of the store instance then pass the store data to the .Provider
via the value
prop. The value
must be an array of [stateObject, reducerFuction]
. Finally, export the CustomReduxStore
instance to be accessible from other component.
// App.jsx
import React from 'react';
import { CustomReduxStore } from 'custom-react-store';
import { initialState, reducer } from './store/counterSlice'
import Counter from './components/Counter/Counter';
// Initialize the store with a name and export the store instance
export const customReduxStore = new CustomReduxStore('Custom Redux Store');
.
// This could be any component
const App = () => {
// Wrap the children with the provider property of the store
// Pass the value to be provided globally to the children components to the *value* prop
return (
<customReduxStore.Provider value={[initialState, reducer]}>
<h3>Custom Redux Store Example</h3>
<Counter />
</customReduxStore.Provider>
);
}
export default App;
Access the store data in the Counter
component. .useStore
method of the store instance returns an array of [stateObject, dispatchFunction]
.
// ./components/Counter/Counter.jsx
import React from 'react';
import { actions } from '../../store/counterSlice';
// import the store instance
import { customReduxStore } from '../../App';
const Counter = () => {
// Destruct the store data
const [ state, dispatch ] = customReduxStore.useStore();
// Use the store data
return (
<div>
<div>{ state.counter }</div>
<div>
<button onClick={() => dispatch(actions.change(-1))}>-</button>
<button onClick={() => dispatch(actions.reset}>reset</button>
<button onClick={() => dispatch(actions.change(+1)}>+</button>
</div>
</div>
);
}
export default Counter;
CustomReduxStore
can be instantiated as many as needed and in any part of the application.
Custom combine store
Custom redux store provides a redux like interface with the combine store feature.
Firstly, we need to setup the store(s).
// ./store/counterSlice/index.js
// Store data instance
export const initialState = {
counter: 0
}
// Reducer to update the store
export const reducer = (state, action) => {
switch (action.type) {
case 'CHANGE':
return { ...state, counter: state.counter + action.payload }
case 'RESET':
return { ...state, counter: 0 }
default:
return state
}
}
// Actions object
export const actions = {
change: (payload) => ({ type: 'CHANGE', payload }),
reset: { type: 'RESET' }
}
Next, we need to combine the store.
// ./store/index.js
import { initialState, reducer } from "./counterSlice";
/**
* Object that combines different store slices
*/
const combineStoreSetup = {
// The format for combining store is as follows
// sliceName: [sliceInitialState, sliceReducer ]
counterStore1: [initialState, reducer],
counterStore2: [initialState, reducer],
};
export default combineStoreSetup;
Import the CustomCombineStore
class and initialize the store outside the react component. Then, Wrap the components you wish to provide store to via .Provider
component of the store instance then pass the store data to the .Provider
via the value
prop. The value
must be an object of {...sliceNames}
, where each slice is an array of [sliceStateObject, sliceReducerFunction]
. Finally, export the CustomCombineStore
instance to be accessible from other component.
// App.js
import React from 'react';
import { CustomCombineStore } from 'custom-react-store';
import { initialState, reducer } from './store'
import Counter from './components/Counter/Counter';
// Initialize the store with a name and export the store instance
export const customCombineStore = new CustomCombineStore('Custom Combine Store');
.
// This could be any component
const App = () => {
// Wrap the children with the provider property of the store
// Pass the value to be provided globally to the children components to the *value* prop
return (
<customCombineStore.Provider value={[initialState, reducer]}>
<h3>Custom Combine Store Example</h3>
<Counter />
</customCombineStore.Provider>
);
}
export default App;
Access the store data in the Counter
component. .useStore
method of the store instance returns an object of { ...sliceNames }
where each slice is an array of [sliceStateObject, sliceDispatchFunction]
.
// ./components/Counter/Counter
import React from 'react';
import { actions } from '../../store/counterSlice';
// import the store instance
import { customCombineStore } from '../../App';
const Counter = () => {
// Destruct the stores data
const { counterStore1, /* counterStore2 */ } = customCombineStore.useStore();
// Access any of the stores
const [ state, dispatch ] = counterStore1;
// Use the store data
return (
<div>
<div>{ state.counter }</div>
<div>
<button onClick={() => dispatch(actions.change(-1))}>-</button>
<button onClick={() => dispatch(actions.reset}>reset</button>
<button onClick={() => dispatch(actions.change(+1)}>+</button>
</div>
</div>
);
}
export default Counter;
CustomCombineStore
can be instantiated as many as needed and in any part of the application.
License
MIT © [ucer without any external dependencies.](https://github.com/ucer without any external dependencies.)
Example
An example use of the store can be found in the example folder.