实现redux中的方法
/*
* createStore 创建REDUX容器
* @PARAMS
* reducer:函数
* @RETURN
* store:{
* getState,
* dispatch,
* subscribe
* }
* */
function createStore(reducer) {
// 创建一个store,STATE用来存储管理的状态信息,LISTENARY用来存储事件池中的方法
// state不用设置初始值,因为dispatch执行REDUCER,STATE没有值,走的是REDUCER中赋值
// 的默认信息,我们自己创建容器的时候就把DISPATCH执行一次
let state, listenAry = [];
// 基于dispatch实现任务派发
function dispatch(action) {
// 执行reducer,修改容器中的状态信息(接收REDUCER的返回值,把返回的信息替换原有的STATE),
// 值得注意的是:我们是把返回值全部替换成STATE,所有要求REDUCER中修改状态之前,要先把
// 原始状态的信息克隆一份,在进行单个的属性修改
state = reducer(state, action);
// 2.通知事件池中方法执行
for (let i = 0; i < listenAry.length; i++) {
let item = listenAry[i];
if (typeof item === 'function') {
item();
} else {
listenAry.splice(i, 1);
i--;//此处的作用是防止数组塌陷
}
}
}
dispatch({ type: '_INIT_DEFAULT_STATE' });//=>容器创建的时候执行一次DISPATCH,目的是把REDUCER中的默认状态信息赋
// 值给redux容器中的状态
//=>GET-STATE :获取容器中的状态信息
function getState() {
// 我们需要保证返回的状态信息不能和容器中的STATE是同一个堆内存(否则外面获取
// 状态信息后,直接就可以修改容器中的状态了,这不符合DISPATCH->REDUCER才能改状
// 态的规范)
return JSON.parse(JSON.stringify(state));//深度克隆
}
// =>SUBSCRIBE:向事件池中追加方法
function subscribe(fn) {
// 向容器中追加方法(去重验证)
let isExit = listenAry.includes(fn);
!isExit ? listenAry.push(fn) : null;
// 2返回一个方法:执行返回的方法会把当前绑定的方法在事件池中移除掉
return function unsubscribe() {
let index = listenAry.indexOf(fn);
listenAry.splice(index, 1);//数组中直接删除前面数组的方法会引起数组塌陷
};
}
return {
dispatch,
getState,
subscribe,
};
}
//let reducer = (state, action) => {
=>state 原有状态信息
=>ACTION: 派发任务时传递的行为对象
// switch (action.type) {
// //根据不同的TYPE执行不同的STATE修改操作
// case TYPE.XXX:
// state = { ...state, n: 5 };
// }
// return state;//返回的state会替换原有的state
//};
//let store = createStore(reducer);
//=>CREATE的时候把REDYCER传递进来,但此时REDUCER比没有执行呢,
// 只有DISPATCH时候才执行,通过执行REDUCER修改容中的状态
//store.dispatch({type:"xxx",...})
//let unsubscribe = store.subscribe(fn);
//unsubscribe(); 移除追加的方法
/*
* combineReducers:REDUCER 合并的方法
* @PARAMS
* 对象,对象中包含了每一个版块对象的REDUCER=>{xxx:function reducer...}
* @RETURN
* 返回的是一个新的REDUCER函数(把这个值赋值给CREATE-STORE)
* 特殊处理:合并REDUCER之后,REDUX容器中的STATE也变为以对应对象管理的模式=>{xxx:{}...}
* */
function combineReducers(reducers) {
//=>REDUCERS:传递劲来的REDUCER对象集合
/*
* {
* vote:function reducer(state={n:0,m:0}){ ... return state}
* person:function reducer(state={baseInfo:""}){ ... return state}
* }
* */
return function reducer(state = {}, action) {
//=>DISPATCH派发执行的时候,执行的是返回的REDUCER,这里也要返回一个最终的STATE对象
// =>替换原有的STATE,而且这个STATE中包含每个模块的状态信息=>{vote:...,person:...}
// =>我们所谓的REDUCER合并,其实就是DISPATCH派发的时候,把每个模块的REDUCER都单独执行一遍
// 把每个模块返回的状态最后在汇总在一起,替换容器中的状态信息
let newState = {};
for (let key in reducers) {
if (!reducers.hasOwnProperty(key)) break;
//reducers[key];每个模块单独的reducer
//state[key]当前模块在REDUX容器中存储的状态信息
//=>返回值是当前模块最新的状态,把它放到NEW-STATE中
newState[key] = reducers[key](state[key], action);
}
return newState;
};
}
store = createStore(reducer);
store.dispatch({ type: 'xxx' });
react-redux中的方法Provider和connect高阶组件的实现
import React from 'react';
import PropTypes from 'prop-types';
/*
* PROVIDER:当前项目的根组件
* 1.接收通过属性传递进来的STORE,把STORE挂载到上下文中,这样当前项目中任何一个组件中,想要
* 使用REDUX中的STORE,直接通过上下文即可
* 2.在组件的RENDER中,把传递给PROVIDER的子元素渲染
* */
class Provider extends React.Component {
//设置上下文信息类型
static childContextTypes = {
store: PropTypes.object,
};
//设置上下文信息值
getChildContext() {
return {
store: this.props.store,
};
}
constructor(props, context) {
super(props, context);
}
render() {
return this.props.children;
}
}
/*
*CONNECT:高阶组件(基于高阶函数:函数柯理化) 创建的组件就是高阶组件
* @PARAMS
* mapStateToProps:回调函数,把REDUX中的部分状态信息挂载到指定组建的属性上
* ```
* `mapStateToProps(state){
* state:REDUX容器中的状态信息
* return{};//=>RETURN对象中有啥,就把啥挂载带属性上
* }
* ```
* mapDispatchToProps:回调函数,把一些需要派发的任务方法也挂载到组件的属性上
* ```
* function mapDispatchToProps(dispatch){
* return {}//=>RETURN 啥就把啥挂载到属性上(返回的方法中有执行dispatch派发任务的操作)
* }
* ```
* @RETURN
* 返回一个新的函数
* =======
* connectHOT
* @PARAMS
* 传递进来的是要操作的组件,我们需要把指定的属性和方法都挂载到当前属性的
* 组件上
* @RETURN
* 返回一个新的组件Proxy(代理组件),在代理组件中,我们要获取Provider在上下文
* 中存储的store,紧接着获取store中的state和dispatch,把mapStateToProps,mapDispatchToProps
* 回调函数执行,接收返回的结果,在把这些结果挂载到Component这个要操作的组件的属性上
* */
function connect(mapStateToProps, mapDispatchToProps) {
return function connectHOT(Component) {
return class Proxy extends React.Component {
// =>获取上下文中的STORE
static contextTypes = {
store: PropTypes.object,
};
// =>获取STORE中的STATE/DISPATCH ,把传递的俩个回调函数执行,接收返回的结果
constructor(props, context) {
super(props, context);
this.state = this.queryMountProps();
}
//=>基于REDUX中的SUBSCRIBE向事件池中追加一个方法,当容器中状态改变,我们需要重新获取
// 最新的状态信息,并且重新把COMPONENT渲染,把最新的状态信息通过属性传递给COMPONENT
componentDidMount() {
this.context.store.subscribe(() => {
this.setState(this.queryMountProps());
});
}
// =>渲染COMPONENT组件,并且把获取的信息(状态,方法)挂载到组件属性上(单独调取
// POXY组件的是时候传递给Component)
render() {
return <Component {...this.state} {...this.props}/>;
}
// =>从redux中获取最新的信息,基于回调函数筛选,返回的是需要挂载到组件属性上的信息
queryMountProps = () => {
let { store } = this.context,
state = store.getState();
let propsState = typeof mapStateToProps === 'function'
? mapStateToProps(state)
: {};
let propsDispatch = typeof mapDispatchToProps === 'function'
? mapDispatchToProps(store.dispatch)
: {};
return { ...propsState, ...propsDispatch };
};
};
};
}
export { Provider };