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
```javascript
const 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]; //分reducer
const 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
```jsx
export {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 【获取仓库】
```jsx
import 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;