Simple State Management Using React Hooks, Inpired By Hyperapp
Created: 1 Sep 2021,Updated: 4 Feb 2022,(0) fork,(0) stars,(0) comments,
useState.js
import { createContext, useContext, useState, useMemo } from 'react';
export const createStore = (state, actions) => {
const set = (obj) =>
obj && typeof obj === 'object'
? ((state = { ...state, ...obj }), state)
: state;
const newActions = Object.keys(actions)
.filter((key) => typeof actions[key] === 'function')
.reduce(
(action, key) => (
(action[key] = (...args) => {
const sop = actions[key](state, action, ...args);
return sop.then && sop.catch
? sop.then(set).catch(set)
: Promise.resolve(sop).then(set);
}),
action
),
{}
);
return { state, actions: newActions };
};
export const StoreContext = createContext();
const customContext = (context) => () => {
const store = useContext(context);
if (process.env.NODE_ENV !== 'production' && !store)
throw new Error('No Store Provided.');
const [state, setState] = useState(store.state);
return useMemo(() => {
const actions = Object.keys(store.actions).reduce((a, b) => {
const set = (s) => (setState(s), s);
a[b] = (...args) =>
store.actions[b](...args)
.then(set)
.catch(set);
return a;
}, {});
return [state, actions];
}, [state]);
};
export const useStore = customContext(StoreContext);
App.js
import { createStore, useStore, StoreContext } from './useState.js';
const store = createStore(
{
count: 0
},
{
increment(state, _) {
return Promise.resolve({
count: state.count + 1
});
},
async decerment(state, _) {
return {
count: state.count - 1
};
},
incrementBy(state, _, payload) {
return {
count: state.count + parseInt(payload)
};
}
}
);
export default function TestingPage() {
return (
<StoreContext.Provider value={store}>
<Testing />
</StoreContext.Provider>
);
}
function Testing() {
const [state, action] = useStore();
return (
<div className="m-8">
<h3>Counter: {state.count}</h3>
<button className="p-1 bg-blue-500 mr-2" onClick={(e) => action.increment()}>
Increment
</button>
<button className="p-1 bg-blue-500 mr-2" onClick={(e) => action.decerment()}>
Decrement
</button>
<button className="p-1 bg-blue-500 mr-2" onClick={(e) => action.incrementBy(10)}>
Increment 10
</button>
</div>
);
}