|
1 | | -# react-redux-global-state-manager |
2 | | -Fully native global state manager using react Hooks. You can use this library instead of Redux or Mobx. also you can access state from all of your components and behavior with them using hooks. |
| 1 | +# react-redux-global-state-manager |
| 2 | + |
| 3 | + |
| 4 | + |
| 5 | +## Work on both `React` and `React-Native` |
| 6 | + |
| 7 | +Fully native `global state manager` using react `Hooks` (React > 16.8). You can use this library instead of Redux or MobX. also you can access state from all of your components and behavior with them using hooks. |
| 8 | + |
| 9 | +A nice state management lib for React that uses the React's useState hook. Which basically means no magic behind the curtains, only pure react APIs being used to share state across components. |
| 10 | + |
| 11 | +# Installation |
| 12 | + |
| 13 | +### yarn |
| 14 | + |
| 15 | + > yarn add react-redux-global-state-manager |
| 16 | +
|
| 17 | +### npm |
| 18 | + |
| 19 | +> npm i react-redux-global-state-manager |
| 20 | +
|
| 21 | +# My recommended Pattern |
| 22 | + |
| 23 | +We use `Redux` with `Reducer` and `Actions` pattern with object reference access to whole actions and stores using single import object (`IntelliSense` work perfectly with it in VSCode) |
| 24 | + |
| 25 | +## Recommended Directory Structure: |
| 26 | +Create these directories structure in your app for state management: |
| 27 | + |
| 28 | +```css |
| 29 | +store/actions/ |
| 30 | +store/stores/ |
| 31 | +store/index.js |
| 32 | +store/storeActions.js |
| 33 | +store/storeNames.js |
| 34 | +``` |
| 35 | + |
| 36 | +## Step 1: Create new store (Redux like) |
| 37 | + |
| 38 | +Create each store separately in `store/stores/` directory according meaningful name. |
| 39 | + |
| 40 | + e.g: Create file for store token information in it > `store/stores/token.store.js ` |
| 41 | + |
| 42 | +>Then add exported name inside `storeNames.js` for use Intellisense friendly accessible. I will explain this way in step 3. |
| 43 | + |
| 44 | + |
| 45 | +e.g: `store/stores/token.store.js` |
| 46 | + |
| 47 | +```js |
| 48 | +import { createStore } from "react-redux-global-state-manager"; |
| 49 | + |
| 50 | +// List of Constant Types |
| 51 | +const types = { |
| 52 | + SET_TOKEN_INFO: "SET_TOKEN_INFO", |
| 53 | +}; |
| 54 | +// define store with name,initialState and reducer |
| 55 | +const token = createStore( |
| 56 | + "token", // unique name for this token store |
| 57 | + { // initialize state object |
| 58 | + token: null, |
| 59 | + public_key: "", |
| 60 | + expire_in: "", |
| 61 | + login_time: "" |
| 62 | + }, |
| 63 | + (state, action) => { // define reducer |
| 64 | + // when a reducer is being used, you must return a new state value |
| 65 | + switch (action.type) { |
| 66 | + case types.SET_TOKEN_INFO: |
| 67 | + return { |
| 68 | + ...state, |
| 69 | + ...action.payload |
| 70 | + }; |
| 71 | + default: |
| 72 | + return state; |
| 73 | + } |
| 74 | + } |
| 75 | +); |
| 76 | + |
| 77 | +export { token, types }; //export token reference and types |
| 78 | + |
| 79 | +``` |
| 80 | + |
| 81 | +## Step 2: Create action file |
| 82 | + |
| 83 | +Create separate action file for each store in `store/stores/` directory according to your store with meaningful name. |
| 84 | + |
| 85 | + e.g: Create file for store token actions in it > `store/actions/token.action.js ` |
| 86 | + |
| 87 | +>Then add exported name inside `storeActions.js` for use Intellisense friendly accessible. I will explain this way in step 3. |
| 88 | + |
| 89 | +e.g: store/actions/token.actions.js |
| 90 | + |
| 91 | +```js |
| 92 | +import { types } from "../stores/token.store.js"; |
| 93 | + |
| 94 | +const token = { |
| 95 | + setTokenInfo: data => { |
| 96 | + return { |
| 97 | + type: types.SET_TOKEN_INFO, |
| 98 | + payload: data |
| 99 | + }; |
| 100 | + } |
| 101 | +}; |
| 102 | + |
| 103 | +export { token }; |
| 104 | + |
| 105 | +``` |
| 106 | + |
| 107 | +> Note: follow the files format similar to others files inside `actions` and `stores` directories. |
| 108 | +
|
| 109 | +## Step 3: Add exported `stores` and `actions` respectively to `storeNames.js` and `storeActions.js` |
| 110 | + |
| 111 | + |
| 112 | +e.g: add `store/stores/token.store.js` into `store/storeNames.js`* |
| 113 | + |
| 114 | +```js |
| 115 | +import { token } from "./stores/token.store.js"; |
| 116 | +import { profileInfo } from "./stores/profileInfo.store.js"; |
| 117 | +// ------ use this object as store identifier invoker in whole app |
| 118 | +const storeNames = { |
| 119 | + token, |
| 120 | + profileInfo, |
| 121 | +}; |
| 122 | +// ------ |
| 123 | +export { storeNames }; // export this object as container for all of our stores. |
| 124 | + |
| 125 | +``` |
| 126 | + |
| 127 | +e.g: add `store/actions/token.action.js` into `store/storeActions.js` |
| 128 | + |
| 129 | +```js |
| 130 | +import { token } from "./actions/token.action.js"; |
| 131 | +import { profileInfo } from "./actions/profileInfo.action.js"; |
| 132 | +// ------ use this object as action function invoker in whole app |
| 133 | +const storeActions = { |
| 134 | + token, |
| 135 | + profileInfo, |
| 136 | +}; |
| 137 | + |
| 138 | +// ------ |
| 139 | +export { storeActions }; // export this object as container for all of our Actions. |
| 140 | +``` |
| 141 | + |
| 142 | +## Step 4: Create one EntryPoint for your store |
| 143 | + |
| 144 | +Create `store/index.js` and add these code into it. |
| 145 | + |
| 146 | +```js |
| 147 | + |
| 148 | +import { useStore, readOnlyStore, dispatchDirectly } from "react-redux-global-state-manager"; |
| 149 | +import { storeNames } from "./storeNames.js"; // All stores references |
| 150 | +import { storeActions } from "./storeActions.js"; // All actions references |
| 151 | + |
| 152 | +// ------ |
| 153 | +export { storeNames, storeActions, useStore, readOnlyStore, dispatchDirectly }; |
| 154 | + |
| 155 | +``` |
| 156 | + |
| 157 | +# Using store in our components |
| 158 | + |
| 159 | +## Import required functions from entry point at `/store/index.js` |
| 160 | + |
| 161 | +```js |
| 162 | +import { |
| 163 | + storeNames, // access all stores reference |
| 164 | + storeActions, // access all actions functions |
| 165 | + useStore, // hook - use this in functional component and return [state,dispatch] |
| 166 | + readOnlyStore, // just return current store value in non-component functions |
| 167 | + dispatchDirectly // To access dispatch in non-component functions |
| 168 | +} from "../shared/globalStore/index"; |
| 169 | +``` |
| 170 | + |
| 171 | +## For use in `functional Components`: |
| 172 | + |
| 173 | +```js |
| 174 | + const [state,dispatch] = useStore(storeNames.token); |
| 175 | + const [profileInfo, dispatch_pi] = useStore(storeNames.profileInfo); |
| 176 | + |
| 177 | + // To call dispatch: dispatch() just take one object. best-practice is to call action function |
| 178 | + const data={ |
| 179 | + token: "402790c1-ec61-4b10-9613-6b926529d0f2", |
| 180 | + public_key: "24d6e775def2404fb21a34fdd8a4e4b0", |
| 181 | + expire_in: "2019-12-14T22:39:10.222Z", |
| 182 | + login_time: "2019-12-13T10:20:15.222Z" |
| 183 | + } |
| 184 | + dispatch(storeActions.token.setTokenInfo(data)) |
| 185 | +``` |
| 186 | + |
| 187 | +> Or use `destructuring` properties: |
| 188 | +
|
| 189 | +```js |
| 190 | + const [{token,public_key,expire_in},dispatch] = useStore(storeNames.token); |
| 191 | +``` |
| 192 | + |
| 193 | +## For use in regular functions (`None-Component functions`): |
| 194 | +If in a situation you (had to) `forced` to `read data from store` or `dispatch` some data in it, you can use this approach. |
| 195 | + |
| 196 | +### Read: |
| 197 | + |
| 198 | +```js |
| 199 | +//read whole token object out of component function, using store name reference |
| 200 | +const token=readOnlyStore(storeNames.token); |
| 201 | +``` |
| 202 | + |
| 203 | +### Write: |
| 204 | + |
| 205 | +```js |
| 206 | +//call dispatch function directly out of component functions. this function take 2 params. |
| 207 | +//arg1= store reference, |
| 208 | +//arg2= action function that return object. |
| 209 | + |
| 210 | +dispatchDirectly(storeNames.token, storeActions.token.setTokenInfo(tokenData)); |
| 211 | +``` |
| 212 | + |
| 213 | +# Functions |
| 214 | + |
| 215 | + |
| 216 | +|Function |Description |Return value | |
| 217 | +|--------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------|---------------------------------| |
| 218 | +|useStore(storeReference) | This function take your `store reference` to access the `current state` and `dispatch` function. Each time the state of the current store going to change, every component that used `useStore()` will be `re-render`. | `[stateObject,dispatchFunction]`| |
| 219 | +|createStore(storeName,initState,reducer) | This function create a new store and return the reference obj to this store. we use this reference to access this store in future | Reference to this store | |
| 220 | +|readOnlyStore(storeReference) | Just return current store value in non-component functions | Current state of specific store | |
| 221 | +|dispatchDirectly(storeReference,action) | To access dispatch in non-component functions | null | |
| 222 | + |
| 223 | + |
| 224 | +## Please subscribe and contribute with me to develop this lib |
| 225 | + |
| 226 | +--- |
| 227 | + |
| 228 | +## Notice: |
| 229 | + |
| 230 | +This library inspired by [https://github.com/jhonnymichel/react-hookstore](https://github.com/jhonnymichel/react-hookstore) |
0 commit comments