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>
  );
}