-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
如何从零实现一个 Redux? #9
Comments
reducex的缺点状态一改动就会触发订阅事件池的所有回调函数; 如果有不怎么熟悉 createStorecreateStore 函数用于创建并且返回一个状态操作对象,以下是对 store 对象的部分类型定义; interface action {
type: string;
[payload: string]: any;
}
type subscribe = (lister: Function) => Function
interface Store {
dispatch: action;
getState: Function;
subscribe: subscribe;
} store 对象主要有有
知道这几个 API 的功能后我们之一来实现吧~ /**
* createStore
* 创建 store 对象,并将对象返回
* @param {(state:{[key:string]:any},action:{type: string,[key:string]:any}) => {[key:string]:any}} reducer
* @param {Function} [middleware] 中间件
* @returns {{dispatch: Function,getState: Function,subscribe: Function}} state 操作对象
*/
function createStore(reducer) {
// store 状态
let state;
//监听队列
let listers = [];
/**
* 获取最新的 state
* @returns {store} state
*/
function getState() {
const { parse, stringify } = JSON;
// 为了安全起见,返回深拷贝后的 state 对象,防止组件随意增加属性造成数据污染
return parse(stringify(state));
}
/**
* 发布函数
* 接受一个 action 对象
* @param {{type: string,[key:string]:any}} action
* @returns {{[key:string]: any}} action
*/
function dispatch(action) {
// 将 action 派发给 reducer 函数进行状态处理,并且更新最新的 state
state = reducer(state, action);
// 状态更新后还得执行以下我们的监听队列,告诉他们我们的 state 更新啦
listers.forEach(observer => typeof observer === 'function' && observer());
// 将此次分发的 action 返回出去
return action;
}
/**
* 订阅函数
* @param {Function} lister 监听函数
* @returns {Function} disconnect 注销监听
*/
function subscribe(lister) {
if (typeof lister !== 'function') {
console.warn(
'The Lister parameter of the subscribe function must be a function'
);
// 返回一个匿名函数,防止报错
return () => {
// 顺便在多提示几下  ̄ω ̄=
console.warn(
'The Lister parameter of the subscribe function must be a function'
);
};
}
return function () {
// 将监听的数组从 listers (监听队列)移除掉
listers = listers.filter(observer => observer !== lister);
};
}
// 初始化 state ,派发一个私有的 action,避免重名影响到状态误改
dispatch({ type: `CODE_ROOKIE_262@@${Date.now().toString(16)}` });
return {
dispatch,
getState,
subscribe
};
} 以上基本实现了
// 定义一个 计数器 reducer
function reducer(state,action){
switch(action.type){
case 'add':
return {...state,count: state.count + 1};
case 'minus':
return {...state,count: state.count - 1};
default:
return state;
}
}
// 创建 Store
const store = createStore(reducer);
// 订阅状态监听
let observer = store.subscribe(function(){
console.log('new state',store.getState())
});
// 派发 action 更改状态
store.dispatch({
type: 'add'
})
// 注销监听
observer() combineReducers有的时候我们的状态是有模块区分的,就和 这个时候就是我们大哥 /**
* 合并多个 reducer 函数
* @param reducers {reducer1: reducer1,reducer2: reducer2,...}
* @returns reducer
*/
function combineReducers(reducers) {
return function reducer(state = {}, action) {
let newState = {};
// 更新每个模块的 state,并且将其最新状态返回
for (var key in reducers) {
newState[key] = reducers[key](state[key], action);
}
return newState;
};
}
const count = function countReducer(state,action){...};
const list = function countReducer(state,action){...};
const reducer = combineReducers({
count: count,
list: list
})
const store = createStore(reducer); applyMiddleware
以上是引用 redux 中文网 可以看出
// redux-logger 是打印状态变更的一个中间件
import logger from 'redux-logger';
import {createStore,applyMiddleware} from 'redux'
function reducer(state,action){}
let store = createStore(reducer,applyMiddleware(logger)) 这个时候我们得给我的上面的 function createStore(reducer,middleware){
//...other code
// 安装 middleware
if(typeof middleware === 'function'){
return middleware(createStore)(reducer)
}
return {
getState: getState,
dispatch: dispatch,
subscribe: subscribe
}
} 我们先从单个中间件 function applyMiddleware(middleware){
return function(createStore){
return function(reducer){
// 创建 store
let store = createStore(reducer);
// 将 store 传入中间件
let middle = middleware(store);
// 将 dispatch 传入中间件返回的函数进行修饰,并返回
let middleDispatch = middle(store.dispatch);
return {
...store,
dispatch: middleDispatch
}
}
}
} 基本的中间件注入是解决了,但是 例如有 const dispatch1 = middleware1(dispatch);
const dispatch2 = middleware(dispatch11); 所以我们是不是可以这样写呢 => 那我们可以封装一函数 在此之前我们可以看下 funcs.reduce((a, b) => (...args) => a(b(...args))); 可以看看简化后的代码 function compose(...funs) {
return arg => {
let res = arg;
for (var i = 0, fl = funs.length; i < fl; i++) {
// 接受返回值,并且将上一个函数的返回值传递给当前函数
res = funs[i](res);
}
return res;
};
} 看完后是不是焕然大悟了哈哈哈,当然用 数组的 function compose(...funs) {
return dispatch => funs.reduce((res, fun) => fun(res), dispatch);
} 关于插件合并的问题我们基本解决了,接下来我们再次修改一下我们的 function applyMiddleware(...middleware){
return function(createStore){
return function(reducer){
// 创建 store
let store = createStore(reducer);
// 将 store 传入中间件
- let middle = middleware(store);
+ let middles = middleware.map(middle => middle(store));
// 将 dispatch 传入中间件返回的函数进行修饰,并返回
- let middleDispatch = middle(store.dispatch);
+ let middleDispatch = compose(...middles)(store.dispatch);
return {
...store,
dispatch: middleDispatch
}
}
}
} |
Redux 是目前 React 框架最火的状态管理工具,但是它与 React 没有任何关系,我们可以通过阅读源码并且模仿实现它才可以更为深刻的了解 Redux 的迷人之处,并且从源码中找出它的不足之处并尝试优化,为此你会如何实现它呢?
The text was updated successfully, but these errors were encountered: