react-redux 是 React 生态中比较(若是不是最的话)流行的一种状态管理方式,而它所依托的 redux,继承了 flux 的衣钵,而且引入了单一数据源、state 为只读、只能经过纯函数修改三大原则。一个最简单的 redux 应用示例:javascript
// https://cn.redux.js.org/
import { createStore } from 'redux'
/** * 这是一个 reducer,形式为 (state, action) => state 的纯函数。 * 描述了 action 如何把 state 转变成下一个 state。 * * state 的形式取决于你,能够是基本类型、数组、对象、 * 甚至是 Immutable.js 生成的数据结构。唯一的要点是 * 当 state 变化时须要返回全新的对象,而不是修改传入的参数。 * * 下面例子使用 `switch` 语句和字符串来作判断,但你能够写帮助类(helper) * 根据不一样的约定(如方法映射)来判断,只要适用你的项目便可。 */
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}
// 建立 Redux store 来存放应用的状态。
// API 是 { subscribe, dispatch, getState }。
let store = createStore(counter)
// 能够手动订阅更新,也能够事件绑定到视图层。
store.subscribe(() => console.log(store.getState()))
// 改变内部 state 唯一方法是 dispatch 一个 action。
// action 能够被序列化,用日记记录和储存下来,后期还能够以回放的方式执行
store.dispatch({ type: 'INCREMENT' })
// 1
store.dispatch({ type: 'INCREMENT' })
// 2
store.dispatch({ type: 'DECREMENT' })
// 1
复制代码
createStore
是 redux 中最基础的 API,它的做用就是返回一个 store
;而这个 store
有三个方法 —— dispatch
, subscribe
和 getState
。其实从方法名上,咱们大体能够推测出 redux 应用了订阅发布模式;该模式能够直接套用下面的模板代码:java
// 开始
// createStore 是一个闭包,维护了 currentState, listeners 私有性;
// 外层想要获取 state,只能经过 getState;
// listeners 没法从外层修改
function createStore(reducer, preloadedState) {
// 每次调用 subscribe,就会向 listeners 数组 push 一个 listener;
// 每次调用 dispatch,listeners 数组中的函数会依次执行;
const listeners = [];
let currentReducer = reducer;
let currentState = preloadedState;
function dispatch(action) {
// 正如示例代码中所展示的,reducer(即 counter) 函数接受 state,action 两个参数
// action 是一个简单对象,有一个 type 属性;
// reducer 中根据 type 执行对应操做,返回新的 state;
currentState = currentReducer(currentState, action);
// 执行 listeners 数组中的全部函数
listeners.forEach(listener => listener());
}
function subscribe(listener) {
listeners.push(listener);
// 返回一个取消订阅的函数
return function unsubscribe() {
let index = listeners.indexOf(listener);
listeners.splice(index, 1);
};
}
// 这个函数的做用就是返回 state
function getState() {
return currentState;
}
return {
dispatch,
subscribe,
getState
};
}
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}
// 测试一下
let store = createStore(counter);
store.subscribe(() => console.log(store.getState()));
store.dispatch({ type: 'INCREMENT' });
// 1
store.dispatch({ type: 'INCREMENT' });
// 2
store.dispatch({ type: 'DECREMENT' });
// 1
复制代码
上面的代码只是为了大体解释一下 redux 的运行机制,实际上是有很多问题的,好比 action 只能是一个简单对象,但咱们的代码中并无进行检测;咱们暂且不去关注这些问题,而是先去实现功能。接下来,修改 dispatch,使它支持函数参数:react
function dispatch(action) {
// 若是传入一个函数,则为这个函数注入 dispatch 和 getState 方法,
// 而且执行这个 action
if (typeof action === 'function') {
return action(dispatch, getState);
}
// 正如示例代码中所展示的,reducer(即 counter) 函数接受 state,action 两个参数
// action 是一个简单对象,有一个 type 属性;
// reducer 中根据 type 执行对应操做,返回新的 state;
currentState = currentReducer(currentState, action);
// 执行 listeners 数组中的全部函数
listeners.forEach(listener => listener());
return action;
}
复制代码
用异步的方式,测试一下:redux
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}
function asyncAdd(dispatch) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(
dispatch({
type: 'INCREMENT'
})
);
}, 1000);
});
}
// 测试一下
let store = createStore(counter);
store.subscribe(() => console.log(store.getState()));
store.dispatch({ type: 'INCREMENT' });
// 1
store.dispatch({ type: 'INCREMENT' });
// 2
store.dispatch(asyncAdd).then(() => store.dispatch(asyncAdd)); // 1s 后 3, 2s 后 4
复制代码
如今,咱们的代码已经具有了 redux + redux-thunk 的功能,并且没有增长新的 API。但咱们是用入侵的方式修改了 dispatch,若是要增长其余新功能怎么办?继续修改 dispatch 么?显然不能这么干。redux 使用中间件的机制,来修改 dispatch:数组
function compose(...funcs) {
if (funcs.length === 0) {
return args => args;
}
if (funcs.length === 1) {
return funcs[0];
}
return funcs.reduce((a, b) => (...args) => a(b(...args)));
}
function applyMiddleware(...middlewares) {
return createStore => (...args) => {
const store = createStore(...args);
let dispatch = () => {
throw new Error('not valid');
};
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args)
};
const chain = middlewares.map(middleware => middleware(middlewareAPI));
// applyMiddleware 本质上,仍是须要去覆盖原来的 dispatch 方法
dispatch = compose(...chain)(store.dispatch);
return {
...store,
dispatch
};
};
}
// 咱们的 thunk
const thunk = ({ dispatch, getState }) => next => action => {
// 这段代码,和咱们上面暴力修改 dispath 的方法,实际上是同样的
if (typeof action === 'function') {
return action(dispatch, getState);
}
return next(action);
};
复制代码
以上就是 redux 以及 redux-thunk 的简单实现,有很多 bug,但愿对你们理解 redux 有点帮助;也建议你们去看看 redux 的源码,其实源码也很短,而且注释很完整。数据结构