Manages global state of React application. Implemented around react-hooks, optimized for both synchronous and asynchronous global-state update operation.
npm install react-hookareact-hooka
================
----------------------------------------------------------------------
Global state management based on React-hooks, with built-in support for both synchronous & queued-asynchronus (FIFO) actions.
----------------------------------------------------------------------
Table of Contents
-----------------
* Introduction
* Install
* Features, Instructions and Glossary
* Store
* Slice
* Actions
* Synchronous Actions
* Asynchronous Actions
* Using react-hooka
* Example
* Live Examples
sh
npm install react-hooka
`
Features, Instructions and Glossary:
$3
Store refers to a global object holding application state and available action on the state in a React application.
Under the hood, store maintains multiple slices, and each of the slice independently manages its state using the actions available on its state.
$3
Slice is an independent subset of the store. A slice holds a subset of application state and defined actions on its state.
Any operation in context of a given slice does not impact other slices within the store. Only the components using (subscribed to) a given slice are notified of the state updates and may perform rerender if required.
$3
Actions are methods responsible to update the state of a slice. Each action is identified by an "Action-Identifier" which must be unique string value within the slice.
Actions methods receives "currentState" as parameter which represents the current snapshot of slice-state.
Actions must return "updatedState". The state returned by the Action is replaced into the slice-state by the "react-hooka".
Note - v2.0.0: State returned by the Action is replaced, not merged into the existing state.
Actions are of two kinds:
1. Synchronous Actions
2. Asynchronous Actions
$3
Synchronous action performs state update in synchronous fashion and are blocking in nature. All state update operations which do not perform I/O or Network operations are cadidates of synchronous actions.
`jsx
// Synchronous Action named "SYNCHRONUS_ACTION_IDENTIFIER"
{
SYNCHRONUS_ACTION_IDENTIFIER: (currentState) => {
try {
const updatedState = {...currentState, n1: 100 };
return updatedState;
} catch (error) {
throw new Error(error.message);
}
}
}
`
$3
Asynchronous action performs state update in asynchronous fashion and are non-blocking in nature. All Asynchronous operations are expected to return a "promise". All state update operations which perform I/O or Network oprations are cadidates of asynchronous actions.
`jsx
// Asynchronous Action named "ASYNCHRONUS_ACTION_IDENTIFIER"
{
ASYNCHRONUS_ACTION_IDENTIFIER: (currentState) => {
return new Promise((resolve, reject) => {
(async () => {
try {
setTimeout(() => {
const updatedState = {...currentState, n1: 100 };
resolve(updatedState);
}, 100);
} catch (error) {
reject(new Error(error.message));
}
})();
});
}
}
`
$3
Using react-hooka is straight forward, which requires following steps:
Initialise store-slice (state and actions belonging to a slice) using "initStoreSlice" method.
"initStoreSlice" method takes 3 parameters:
1. sliceIdentifier: Apllication wide unique string value to identify store-slice.
2. actions: An object holding all the "actions" to be performed on the slice-state. All actions within the "actions" object need to have string "Action-Identifier" which should be unique within the slice.
3. initialState: An object having initial state of the slice.
`jsx
import { initStoreSlice } from "react-hooka";
const actions = {
SYNCHRONUS_ACTION_IDENTIFIER: (currentState) => {
try {
const updatedState = {...currentState, n1: 100 };
return updatedState;
} catch (error) {
throw new Error(error.message);
}
},
ASYNCHRONUS_ACTION_IDENTIFIER: (currentState) => {
return new Promise((resolve, reject) => {
(async () => {
try {
setTimeout(() => {
const updatedState = {...currentState, n2: 200 };
resolve(updatedState);
}, 100);
} catch (error) {
reject(new Error(error.message));
}
})();
});
}
};
const initialState = {
n1: 10,
n2: 20,
n3: 30
};
initStoreSlice("TEST_STORE", actions, initialState);
`
Use "react-hooka" in React component for state management.
1. Import useStore hook from "react-hooka".
`jsx
import { useStore } from "react-hooka";
`
2. Use the useStore hook with the slice-name of the slice in context.
`jsx
const {state, dispatch, dispatchAsync} = useStore("TEST_STORE");
`
state represents the current state of the slice-state.
dispatch method can be used to perform synchronous (blocking) operation on slice-state.
dispatchAsync method can be used to perform asynchronous (non-blocking) operation on slice-state.
OPTIONAL OPTOUT from rerendering of React-components on slice-state updates.
There might be cases when React-components are only performing actions but not displaying the state (such as a FORM only adding new items to state but not displaying existing items.). In such cases React-components can optout rerenders by passing "false" to the 2nd parameter shouldTriggerRerender of useStore hook.
By default, value of shouldTriggerRerender is true, thus all slice-state updates will trigger rerender on React-components which are using useStore hook.
`jsx
const { state, dispatch, dispatchAsync } = useStore("TEST_STORE", false);
OR
// Not using "state" at all.
const { dispatch, dispatchAsync } = useStore("TEST_STORE", false);
`
Delete a store-slice if needed.
If a store-slice is no more needed, it can be deleted from the global-store. deleteStoreSlice method of "react-hooka" can be used to delete a store-slice.
`jsx
import { deleteStoreSlice } from "react-hooka";
deleteStoreSlice("SLICE_NAME");
`
$3
1. Configure store slice:
`jsx
// FILE: testStore.js
import { initStoreSlice } from "react-hooka";
const init = () => {
const actions = {
UPDATE1: (currentState) => {
try {
const updatedState = {...currentState, n1: 100 };
return updatedState;
} catch (error) {
throw new Error(error.message);
}
},
UPDATE2: (currentState) => {
try {
const updatedState = {...currentState, n2: 200 };
return updatedState;
} catch (error) {
throw new Error(error.message);
}
},
UPDATE3: (currentState) => {
try {
const updatedState = {...currentState, n3: 300 };
return updatedState;
} catch (error) {
throw new Error(error.message);
}
},
UPDATE1_ASYNC: (currentState) => {
return new Promise((resolve, reject) => {
(async () => {
try {
setTimeout(() => {
const updatedState = {...currentState, n1: 1000 };
resolve(updatedState);
}, 100);
} catch (error) {
reject(new Error(error.message));
}
})();
});
},
UPDATE2_ASYNC: (currentState) => {
return new Promise((resolve, reject) => {
(async () => {
try {
setTimeout(() => {
const updatedState = {...currentState, n2: 2000 };
resolve(updatedState);
}, 500);
} catch (error) {
reject(new Error(error.message));
}
})();
});
},
UPDATE3_ASYNC: (currentState) => {
return new Promise((resolve, reject) => {
(async () => {
try {
setTimeout(() => {
const updatedState = {...currentState, n3: 3000 };
resolve(updatedState);
}, 800);
} catch (error) {
reject(new Error(error.message));
}
})();
});
}
};
const initialState = {
n1: 10,
n2: 20,
n3: 30
};
initStoreSlice("TEST_STORE", actions, initialState);
};
export default init;
`
2. Initialize store slice:
`jsx
// FILE: index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import initTestStore from "./store/testStore";
// Initialising "TEST_STORE"
initTestStore();
const rootElement = document.getElementById("root");
ReactDOM.render(
,
rootElement
);
`
3. Managing state in component:
`jsx
// FILE: App.js
import React from "react";
import { useStore } from "react-hooka";
import "./styles.css";
export default function App() {
const { state, dispatch, dispatchAsync } = useStore("TEST_STORE");
const SyncUpdate = () => {
dispatch("UPDATE1");
dispatch("UPDATE2");
dispatch("UPDATE3");
};
const AsyncUpdate = () => {
dispatchAsync("UPDATE1_ASYNC");
dispatchAsync("UPDATE2_ASYNC");
dispatchAsync("UPDATE3_ASYNC");
};
return (
1. {state.n1}
2. {state.n2}
3. {state.n3}
);
}
``