async-reducer-context
Version:
通过react-context,useReducer替代redux,可扩展支持与redux周边middleware中间件,通过useModel(['key'])可获取state和dispatch,其中useModel已做到获取的属性值变化,组件才会重新渲染,摆脱useContext因context中无关数据导致的重复渲染问题。
106 lines (105 loc) • 3.74 kB
JavaScript
import React from 'react';
import isEqual from 'lodash/isEqual';
import get from 'lodash/get';
import Subs from './sub';
var createContext = React.createContext, useState = React.useState, useEffect = React.useEffect, useMemo = React.useMemo, useReducer = React.useReducer, useRef = React.useRef, useContext = React.useContext;
function createReducer(initState, actionMap) {
if (initState === void 0) { initState = {}; }
var handles = {};
// fix for reducer hook one params.
if (!actionMap) {
handles = initState;
}
else {
handles = actionMap;
}
return function (state, action) {
if (state === void 0) { state = initState; }
var type = action.type;
if (handles[type]) {
return handles[type](state, action.payload);
}
return state;
};
}
// provide getState for middleware.
var Store = /** @class */ (function () {
function Store() {
}
Store.prototype.getState = function () {
return this.state;
};
Store.prototype.set = function (value) {
this.state = value;
};
return Store;
}());
export default function createRoot(reducers, enhancer) {
var context = createContext({});
var subContext = createContext({});
var reducer = createReducer(reducers);
var middlewareSub = new Subs();
var store = new Store();
var enhanceDispatch;
var ready = function (callback) {
middlewareSub.add(callback);
};
var useModel = function (deps) {
if (deps === void 0) { deps = []; }
var memorizeDeps = useMemo(function () { return deps; }, []);
if (!memorizeDeps.length) {
return useContext(context);
}
var container = useContext(subContext);
var value = container.state, subs = container.subs;
var _a = useState(get(value, memorizeDeps)), state = _a[0], setState = _a[1];
var prevDepsRef = useRef(state);
useEffect(function () {
var observer = function () {
var prev = prevDepsRef.current;
var curr = get(container.state, memorizeDeps);
if (!isEqual(prev, curr)) {
setState(curr);
}
prevDepsRef.current = curr;
};
subs.add(observer);
return function () {
subs.delete(observer);
};
}, []);
return [state, container.dispatch];
};
var reducerProxy = function (s, payload) {
var n = reducer(s, payload);
store.set(n);
return n;
};
var Provider = function (_a) {
var value = _a.value, children = _a.children;
var _b = useReducer(reducerProxy, value), state = _b[0], dispatch = _b[1];
if (enhancer && typeof enhancer === 'function') {
enhanceDispatch = enhanceDispatch || enhancer({ getState: store.getState, dispatch: dispatch });
}
else {
enhanceDispatch = dispatch;
}
var ref = useRef({ state: value, subs: new Subs(), dispatch: enhanceDispatch });
useEffect(function () {
ref.current.state = state;
ref.current.dispatch = enhanceDispatch;
ref.current.subs.notify();
});
// 异步调用middleware,特别为run(rootSaga)提供
useEffect(function () {
middlewareSub.notify();
}, []);
return (React.createElement(context.Provider, { value: { state: state, dispatch: enhanceDispatch } },
React.createElement(subContext.Provider, { value: ref.current }, children)));
};
return {
Provider: Provider,
useModel: useModel,
ready: ready,
};
}