summaryrefslogtreecommitdiff
path: root/src/components/StateProvider.js
diff options
context:
space:
mode:
authorHaishan <[email protected]>2019-12-20 17:45:05 +0800
committerHaishan <[email protected]>2019-12-20 17:45:05 +0800
commitd81592ec970d207d4e37beb6c275ad6b77979e39 (patch)
tree33aac796297864d95307f21d6a9aa790e3c33c09 /src/components/StateProvider.js
parent040c5de04a75415490f9c478d931b7707bfa2486 (diff)
feat: support proxy provider
Diffstat (limited to 'src/components/StateProvider.js')
-rw-r--r--src/components/StateProvider.js79
1 files changed, 79 insertions, 0 deletions
diff --git a/src/components/StateProvider.js b/src/components/StateProvider.js
new file mode 100644
index 0000000..adb1b24
--- /dev/null
+++ b/src/components/StateProvider.js
@@ -0,0 +1,79 @@
+import React from 'react';
+import produce, * as immer from 'immer';
+
+const {
+ createContext,
+ memo,
+ useRef,
+ useEffect,
+ useCallback,
+ useContext,
+ useState
+} = React;
+
+const StateContext = createContext(null);
+const DispatchContext = createContext(null);
+
+export { immer };
+
+export function useStoreState() {
+ return useContext(StateContext);
+}
+
+export function useStoreDispatch() {
+ return useContext(DispatchContext);
+}
+
+export default function Provider({ initialState, children }) {
+ const stateRef = useRef(initialState);
+ const [state, setState] = useState(initialState);
+ const getState = useCallback(() => stateRef.current, []);
+ useEffect(() => {
+ if (process.env.NODE_ENV === 'development') {
+ window.getState2 = getState;
+ }
+ }, [getState]);
+ const dispatch = useCallback(
+ (actionId, fn, thunk) => {
+ // if (thunk) return thunk(dispatch, getState);
+ if (typeof actionId === 'function') return actionId(dispatch, getState);
+
+ const stateNext = produce(getState(), fn);
+ if (stateNext !== stateRef.current) {
+ if (process.env.NODE_ENV === 'development') {
+ // eslint-disable-next-line no-console
+ console.log(actionId, stateNext);
+ }
+ stateRef.current = stateNext;
+ setState(stateNext);
+ }
+ },
+ [getState]
+ );
+
+ return (
+ <StateContext.Provider value={state}>
+ <DispatchContext.Provider value={dispatch}>
+ {children}
+ </DispatchContext.Provider>
+ </StateContext.Provider>
+ );
+}
+
+export function connect(mapStateToProps) {
+ return Component => {
+ const MemoComponent = memo(Component);
+ function Connected(props) {
+ const state = useContext(StateContext);
+ const dispatch = useContext(DispatchContext);
+ const mapped = mapStateToProps(state, props);
+ const nextProps = {
+ ...props,
+ ...mapped,
+ dispatch
+ };
+ return <MemoComponent {...nextProps} />;
+ }
+ return Connected;
+ };
+}