diff options
| author | Haishan <[email protected]> | 2019-12-20 17:45:05 +0800 |
|---|---|---|
| committer | Haishan <[email protected]> | 2019-12-20 17:45:05 +0800 |
| commit | d81592ec970d207d4e37beb6c275ad6b77979e39 (patch) | |
| tree | 33aac796297864d95307f21d6a9aa790e3c33c09 /src/components/StateProvider.js | |
| parent | 040c5de04a75415490f9c478d931b7707bfa2486 (diff) | |
feat: support proxy provider
Diffstat (limited to 'src/components/StateProvider.js')
| -rw-r--r-- | src/components/StateProvider.js | 79 |
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; + }; +} |
