redux相信使用react进行开发项目的过程中是必然会使用到的第三方库,并且他相比于vuex来说有很大的独立性,他并不依赖于react语言包。你对于redux的源码以及中间件有深入理解吗?
redux工作流
redux的工作流程:派发一个dispatch事件会经过store里面的reducer函数在改变初始的state状态,当state发生变化又会通过store的forceUpdate进行对于组件的强制更新。
redux使用以及中间件的应用
redux只是能支持同步内容的执行,并且只能使用对象的形式作为action传到reducer中作为参数,如果要用函数作为参数传递的时候,redux就会报错,因此需要借助于一些中间件进行支持!
## 创建store,src/store/index.js
import {createStore} from "redux";
function countReducer(state = 0, action) {
switch (action.type) {
case "ADD":
return state + 1;
case "MINUS":
return state - 1;
default:
return state;
}
}
const store = createStore(countReducer);
export default store;
## 应⽤中间件
import { createStore, applyMiddleware } from "redux";
import logger from "redux-logger";
import thunk from "redux-thunk";
import counterReducer from './counterReducer'
const store = createStore(counterReducer, applyMiddleware(thunk, logger));
import { createStore, applyMiddleware } from "redux";
代码我们可以看出redux会抛出两个方法:一个是createStore,另一个是应用中间件:applyMiddleware
const store = createStore(counterReducer, applyMiddleware(thunk, logger));
从代码可以看出createStore是一个函数,并且reducer以及应用中间件函数式作为参数进行执行
redux在组件中的使用
import React, {Component} from "react";
import store from "../store/";
export default class ReduxPage extends Component {
componentDidMount() {
this.unsubscribe = store.subscribe(() => {
this.forceUpdate();
});
}
componentWillUnmount() {
if (this.unsubscribe) {
this.unsubscribe();
}
}
add = () => {
store.dispatch({type: "ADD"});
};
asyAdd = () => {
store.dispatch((dispatch, getState) => {
setTimeout(() => {
dispatch({type: "ADD"});
}, 1000);
});
};
promiseMinus = () => {
store.dispatch(
Promise.resolve({
type: "MINUS",
payload: 100
})
);
};
render() {
return (
<div>
<h3>ReduxPage</h3>
<p>{store.getState()}</p>
<button onClick={this.add}>add</button>
<button onClick={this.asyAdd}>asyAdd</button>
<button onClick={this.promiseMinus}>promiseMinus</button>
</div>
);
}
}
从在组件的使用中可以看出redux是有dispatch方法用来派发执行时间,getState是用来获取最新的state状态,subscribe是用来进行强制更新的回调。
综上所述,我们对于源码有以下几点的实现:
1、createStore函数的实现,并且抛出了getState、dispatch、subscribe 函数
2、applyMiddleware函数的实现,核⼼任务是实现函数序列执⾏。
源码
1、createStore函数 主要原理是使用了发布订阅模式
export default function createStore(reducer, enhancer) {
// enhancer是应用中间件函数
if (enhancer) {
// enhancer需要对于dispatch进行加强
return enhancer(createStore)(reducer);
}
// 存储当前状态
let currentState;
// 存储订阅时间的强制更新函数
let currentListeners = [];
// 获取store state获取
function getState() {
return currentState;
}
// 修改状态
function dispatch(action) {
// 更新state状态并进行组件的更新
currentState = reducer(currentState, action);
currentListeners.forEach(listener => listener());
}
function subscribe(listener) {
//收集组件更新方法
currentListeners.push(listener);
return () => {
// 简单置空,大家可以自己实现过滤
currentListeners = [];
};
}
// 派发一个唯一的函数名,以获取最初始化的state状态
dispatch({type: "KKKKREDUX/OOOOOO"});
return {
getState,
dispatch,
subscribe
};
}
2、applaymiddlware的实现
export default function applyMiddleware(...middlewares) {
return createStore => reducer => {
let store = createStore(reducer);
// 这是原版的dispatch,这个dispatch只能接受plain object,不能处理异步、promise
let dispatch = store.dispatch;
const midApi = {
getState: store.getState,
dispatch: (action, ...args) => dispatch(action, ...args)
};
const middlewaresChain = middlewares.map(middleware => middleware(midApi));
dispatch = compose(...middlewaresChain)(store.dispatch);
return {
...store,
// 加强版的dispatch
dispatch
};
};
}
// 对于中间件的处理,使用的是组合函数即高阶函数
function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg;
}
if (funcs.length === 1) {
return funcs[0];
}
return funcs.reduce((a, b) => (...args) => a(b(...args)));
}