UNPKG

@restate/core

Version:

_Restate_ is a predictable, easy to use, easy to integrate, typesafe state container for [React](https://reactjs.org/).

77 lines (76 loc) 2.46 kB
import { current } from "immer"; import { useContext } from "react"; import { isFunction } from "./utils"; function createNextHook(provider, scope) { function useNextHook(selector, trace) { const store = useContext(provider); const outerSelector = scope ? scope : (state) => state; function updateNestedState(subState, nextValue) { const proxy = getProxy({ subState, selector, outerSelector }); mutateNestedObject({ proxy, nextValue }); return subState; } function updateState(updateFunctionOrNextState) { return store.next((currentState) => { if (isFunction(updateFunctionOrNextState)) { const subState = selector(outerSelector(currentState)); return updateFunctionOrNextState(subState); } else { const nextValue = updateFunctionOrNextState; return updateNestedState(currentState, nextValue); } }, trace); } return updateState; } return useNextHook; } function getProxy(props) { const { subState, selector, outerSelector } = props; const unfrozenSupState = Object.isFrozen(subState) ? Object.assign({}, current(subState)) : subState; let path = []; const proxyAccess = (parent) => ({ get(target2, key) { if (Array.isArray(target2) && isNaN(key)) { return target2[key]; } if (key === "___restate_parent___") { return parent; } path.push({ parent, target: target2, key, idx: Array.isArray(parent) ? parent.indexOf(target2) : -1 }); if (typeof target2[key] === "object" && target2[key] !== null) { return new Proxy(target2[key], proxyAccess(target2)); } else if (Array.isArray(target2) && !isNaN(key)) { return new Proxy(target2[key], proxyAccess(target2)); } else { return target2[key]; } } }); const proxy = new Proxy(unfrozenSupState, proxyAccess(unfrozenSupState)); const target = selector(outerSelector(proxy)); if (Array.isArray(target.___restate_parent___)) { return { ...path.at(-1), isArray: true }; } return { ...path.at(-1), isArray: false, idx: -1 }; } function mutateNestedObject(props) { const { proxy, nextValue } = props; const { target, key, isArray, idx, parent } = proxy; if (isArray && typeof parent[idx] === typeof nextValue) { parent[idx] = nextValue; } else { target[key] = nextValue; } } export { createNextHook };