redux
实现 createStore
- https://github.com/reduxjs/redux/blob/master/src/createStore.ts
src/redux/index.js
export {default as createStore} from './createStore'export {default as bindActionCreators} from './bindActionCreators'export {default as combineReducers} from './combineReducers'export {default as compose} from './compose'export {default as applyMiddleware} from './applyMiddleware'
src/redux/createStore.js
```jsx import ActionTypes from ‘./utils/actionTypes’
/** createStore 创建仓库
- redux 应用中,只能有一个 store,只能有一个 reducer,只能有一个 state;它们都是单例的
- @param {*} reducer 处理器
@param {} initState 仓库的初始状态 / function createStore(reducer, initState){ let listeners = []; //监听函数存储数组 let state = initState; //定义状态变量
// 获取状态 function getState(){ return state; }
// 派发action function dispatch(action){ state = reducer(state, action); // 接收reducer,计算新的state listeners.forEach(fn => fn()); //每派发一次动作,执行所有的监听函数 return action; //除了 react ssr 用到了这个返回,其它地方基本用不到 }
/** 订阅
- @param {*} listener 监听函数
- @returns 返回一个函数,用于销毁此监听函数 */ function subscribe(listener){ listeners.push(listener); return () => { listeners.filter(item => item !== listener); } }
// 初始化state(在创建store的时候,会先派发一次action,让reducer设置的默认值生效) dispatch({ type: ActionTypes.INIT });
const store = { getState, dispatch, subscribe, } return store; }
export default createStore;
<a name="ALVRW"></a>##### src/redux/utils/actionTypes.js```javascriptconst randomString = () =>Math.random().toString(36).substring(7).split('').join('.')const ActionTypes = {INIT: `@@redux/INIT${randomString()}`,}export default ActionTypes
实现 bindActionCreators
- https://github.com/reduxjs/redux/blob/master/src/bindActionCreators.ts
src/redux/bindActionCreators.js
```javascript /** bindActionCreator 绑定 action创建者 和 dispatch方法- @param {*} actionCreator action创建者
- @param {} dispatch 派发方法 / function bindActionCreator(actionCreator, dispatch){ return function (…args){ return dispatch(actionCreator.apply(this, args)); } }
/** bindActionCreators 绑定 action创建者们 和 dispatch方法
- @param {*} actionCreators action创建者们
@param {} dispatch 派发方法 / function bindActionCreators(actionCreators, dispatch){ if (typeof actionCreators === ‘function’){ return bindActionCreator(actionCreators, dispatch); }
if (typeof actionCreators !== ‘object’ || actionCreators === null){ throw new Error(
bindActionCreators expected an object or a function .); }const boundActionCreators = {}; for (const key in actionCreators){ const actionCreator = actionCreators[key]; if (typeof actionCreator === ‘function’){ boundActionCreators[key] = bindActionCreator(actionCreator, dispatch); } } return boundActionCreators; }
export default bindActionCreators;
<a name="OCmhZ"></a>## 实现 combineReducers- [https://github.com/reduxjs/redux/blob/master/src/combineReducers.ts](https://github.com/reduxjs/redux/blob/master/src/combineReducers.ts)<a name="VrQlz"></a>##### src/redux/combineReducers.js```jsx/** combineReducers 把一个 reducers 对象变成一个 reducer 函数** @param {*} reducers 样式如: {reducer1: reducer1, reducer2, ...}*/function combineReducers(reducers){/** 返回一个函数,就是 根reducers** @param {*} state 根reducers的老状态,样式如:{reducer1: reducer1State, reducer2: reducer2State, ...}*/function rootReducer(state={}, action){let nextState = {}; //根reducers的新状态for (let key in reducers){const reducer = reducers[key]; //分reducerconst previousStateForKey = state[key]; //分reducer的老状态const nextStateForKey = reducer(previousStateForKey, action); //分reducer的新状态nextState[key] = nextStateForKey;}return nextState;}return rootReducer;}export default combineReducers;
实现 compose
- https://github.com/reduxjs/redux/blob/master/src/compose.ts
src/redux/compose.js
function compose(...fns){return fns.reduce((a, b) => (...args) => a(b(...args)));}export default compose;
实现 applyMiddleware
- https://github.com/reduxjs/redux/blob/master/src/applyMiddleware.ts
src/redux/applyMiddleware.js
```jsx import compose from ‘./compose’;
function applyMiddleware(…middlewares){ return function(createStore){ return function(reducer){ let store = createStore(reducer); //先创建原生的store let dispatch; //指向改造后的dispatch方法 let middlewareAPI = { getState: store.getState, dispatch: action => dispatch(action), }
let chain = middlewares.map(item => item(middlewareAPI));// let [fn1, fn2, fn3, ...] = chain;// dispatch = fn1(fn2(fn3(store.dispatch)));dispatch = compose(...chain)(store.dispatch); //改写dispatch方法return {...store, dispatch};}
} } export default applyMiddleware;
// 中间件格式 (以promise中间件格式为例) // function promise(store){ // return function(next){ // return function(action){ // if (typeof action.then === ‘function’){ // return action.then(newAction => store.dispatch(newAction)); // } // return next(action); // } // } // }
<a name="nnpDV"></a># react-redux[https://github.com/reduxjs/react-redux](https://github.com/reduxjs/react-redux)<a name="FmNxK"></a>## 实现 Provider[https://github.com/reduxjs/react-redux/blob/master/src/components/Provider.js](https://github.com/reduxjs/react-redux/blob/master/src/components/Provider.js)<a name="HFOCV"></a>##### src/react-redux/index.js```jsxexport {default as Provider} from './Provider';export {default as ReactReduxContext} from './ReactReduxContext';
src/react-redux/ReactReduxContext.js
import React from 'react';const ReactReduxContext = React.createContext();export default ReactReduxContext;
src/react-redux/Provider.js
import React from 'react';import ReactReduxContext from './ReactReduxContext';function Provider(props){const value = {store: props.store};// Provider 的下层组件都可以通过 ReactReduxContext 获取value值return (<ReactReduxContext.Provider value={value}>{props.children}</ReactReduxContext.Provider>)}export default Provider;
实现 connect
https://github.com/reduxjs/react-redux/tree/master/src/connect
import React from 'react';import ReactReduxContext from './ReactReduxContext';import {bindActionCreators} from '../redux';/** connect 把组件和仓库进行关联** @param {*} mapStateToProps 把 仓库状态 映射为属性* @param {*} mapDispatchToProps 把绑定后的 actions对象 映射为属性*/function connect(mapStateToProps, mapDispatchToProps){return function(OldComponent){return function (props){const {store} = React.useContext(ReactReduxContext);const {getState, dispatch, subscribe} = store;// 映射 state 为属性const prevState = getState(); //获取仓库中的总状态let stateProps = mapStateToProps(prevState);stateProps = React.useMemo(() => stateProps, [stateProps]);// 映射 绑定后的 actions对象 为属性const dispatchProps = React.useMemo(() => {let dispatchProps;if (typeof mapDispatchToProps === 'object'){dispatchProps = bindActionCreators(mapDispatchToProps, dispatch);} else if (typeof mapDispatchToProps === 'function'){dispatchProps = mapDispatchToProps(dispatch);} else {dispatchProps = {dispatch};}return dispatchProps;}, [dispatch])// useReducer解构出来是 [state, dispatch],// dispatch函数内部处理state的更新逻辑,如果state发生了变化,就会从根组件开始把整个应用更新一下。// 利用useReducer的这个特性,仓库订阅这个dispatch函数后,仓库每次分发之后,就会更新应用。const [, forceUpdate] = React.useReducer(x=>x+1, 0);React.useEffect(() => {return subscribe(forceUpdate);}, [subscribe])return <OldComponent {...props} {...stateProps} {...dispatchProps} />}}}export default connect;
类组件
// 类组件实现function connect2(mapStateToProps, actions){return function(OldComponent){return class extends React.Component {static contextType = ReactReduxContext;componentDidMount(){this.unsubscribe = this.context.store.subscribe(() => this.forceUpdate());}componentWillUnmount(){this.unsubscribe();}render (){const {store} = this.context;const prevState = store.getState();const stateProps = mapStateToProps(prevState);const dispatchProps = bindActionCreators(actions, store.dispatch);return <OldComponent {...this.props} {...stateProps} {...dispatchProps} />}}}}
实现 useDispatch、useSelector、useStore
- https://github.com/reduxjs/react-redux/tree/master/src/hooks
src/react-redux/index.js
export {useDispatch, useSelector, useStore} from './hooks';
src/react-redux/hooks/index.js
export {default as useDispatch} from './useDispatch';export {default as useSelector} from './useSelector';export {default as useStore} from './useStore';
src/react-redux/hooks/useReduxContext.js 【获取redux的上下文】
```jsx import React from ‘react’; import ReactReduxContext from ‘../ReactReduxContext’;
export function useReduxContext(){ const contextValue = React.useContext(ReactReduxContext); return contextValue; } export default useReduxContext;
<a name="MfFmD"></a>##### src/react-redux/hooks/useStore.js 【获取仓库】```jsximport useReduxContext from './useReduxContext';function useStore(){const {store} = useReduxContext();return store;}export default useStore;
src/react-redux/hooks/useDispatch.js 【获取仓库分发(store.dispatch)】
import useReduxContext from './useReduxContext';function useDispatch(){const {store} = useReduxContext();return store.dispatch;}export default useDispatch;
src/react-redux/hooks/useSelector.js 【获取状态映射函数(mapStateToProps)】
import React from 'react';import useReduxContext from './useReduxContext';function useSelector(selector){const {store} = useReduxContext();const {getState, subscribe} = store;const state = getState(); //获取总状态const selectedState= selector(state); //获取分状态// 添加订阅,让组件刷新const [, forceUpdate] = React.useReducer(x=>x+1, 0);React.useEffect(() => {return subscribe(forceUpdate);}, [subscribe])return selectedState;}export default useSelector;
redux-logger 日志中间件

// 日志中间件的真正实现(只要是中间件,格式都是定死的)function logger(store){return function(next){// 最终返回 改写后的 dispatch 方法return function(action){let styleGrey = 'color: #9E9E9E';console.group(`%c action %c ${action.type} %c @ ${new Date()}`, styleGrey, 'color: #000', styleGrey);console.log('%c prev state', styleGrey, store.getState(), );console.log('%c action', 'color: #03A9F4', action);next(action);console.log('%c next state', 'color: #4CAF50', store.getState());console.groupEnd();}}}export default logger;
redux-thunk 函数中间件
- https://github.com/reduxjs/redux-thunk/blob/master/src/index.js
```jsx
// 原生的 store.dispatch 只支持传递普通对象,不能接受函数,也不能接收promise。
// 为了要让其支持,添加 支持函数的中间件
function thunk(store){
return function(next){
return function(action){
} } }// 如果派发的action是一个函数,就让它执行if (typeof action === 'function'){// 如果这里第一个参数传递next(即原生的store.dispatch方法),// 那么函数内 dispatch 有可能还是派发的函数。那样的话就报错了。return action(store.dispatch, store.getState);}// 如果不是函数,则意味着不需要自己处理。直接调用下一个dispatch方法即可。return next(action);
export default thunk;
<a name="EBM9t"></a># redux-promise Promise中间件- [https://github.com/redux-utilities/redux-promise/blob/master/src/index.js](https://github.com/redux-utilities/redux-promise/blob/master/src/index.js)```jsx// 添加支持promise的中间件function promise(store){return function(next){return function(action){if (typeof action.then === 'function'){return action.then(newAction => store.dispatch(newAction));}return next(action);}}}export default promise;
