彻底搞懂React-redux

滴水能把石穿透,万事功到自然成—zZ先森

一张图搞懂Redux运行原理

前言

众所周知,不管是react-redux还是vuex,都是参考于redux的公共状态管理机制。那么搞清楚redux的运行原理,也就搞明白了俩大视图框架的公共状态的一个管理模式。接下来,让我们探究一下它到底是如何做到的。

概括Redux的运行原理

看到首图很懵吧?首先,以我的理解,先概括一下上图所表达的Redux运行原理。

  • 创建一个仓库: 创建仓库,用来存储和管控公共状态。

不难理解,管理公共状态,首先得给他找个地方存储,我把它称为仓库。仓库里有俩个地方分别存放了状态和修改状态的事件,称为状态池和事件池,仓库并提供了操作状态和事件的方法。

  • 通过store.getState()获取仓库中的状态

各个组件通过此方法获取用到的公共状态,作为渲染视图的数据。

  • reducer 充当了仓库的管理角色,每个组件操做状态都得通过reducer。

reducer作为英文单词是减速器、缩减者的意思。在这里的意思是操作状态,管理行为,让组件更加有秩序地、有规则地从仓库里获取状态信息。reducer是一个函数,有俩个参数分别是:【state】【action】,在接收组件dispatch传递进来的行为对象,传递给action,进而做相应的处理。action是一个对象,并保证type属性的存在,用来识别该行为。state携带的就是仓库的初始数据,仓库只不过是给reducer提供一个存储数据的地方。通过对action的操作返回最新修改后的状态信息,同时把仓库中的状态修改了。

  • 通过store.subscribe()往仓库的事件池中订阅方法

各个组件为了后期能获取到最新的状态,提前向组件中订阅修改自己状态的方法,一旦仓库中的状态改变,组件会重新渲染。

store.subscribe()方法执行的返回值是从事件池中移除方法的函数:unsubscribe()

  • 通过store.dispatch()派发一个任务告知reducer修改仓库中的状态。派发的就是一个带有type的对象,通过type来标识修改哪个状态。

最后各个组件都能有效的实时更新,实现了公共状态的管理以及各个组件之间的通信。

手写Redux源码以及优化

  • 提供五个方法

    • dispatch
    • subscribe
    • getState
    • replaceRedecer
    • [$$observable]:observable

  • Redux源码优化

    • 用户使用getState,克隆一份新的状态,防止直接修改

    • 对于添加事件池中,做去重处理

    • 防止在reducer中直接修改状态

      克隆一份新的状态,并返回

      我们知道确实是通过派发任务通知reducer去修改状态,但是我们在操作状态的时候为了能一次性更新,且在修改的时候不破坏原有的状态,防止造成状态的混乱,有必要克隆一份新的状态。在我们使用reducer的时候,也是新克隆一份。

      • 深克隆(推荐)
      • JSON.parse(JSON.stringify(xxx))

    • 对于状态没有更新,我们不通知事件池中的方法执行,从而提高性能。用深比较。

//优化一 深克隆

exportcloneDeep(obj){

if(obj===null) return null;

if(typeof obj!=="function") return obj;

if(obj instanceof RegExp) return new RegExp(obj);

if(obj instanceof Date) return enw Date(obj);

letclone = new obj.constructor;

Object.keys(obj).forEach(item=>{

clone[item] = cloneDeep(obj[item])

})

returnclone

}

exportfunction createStore(reducer){

if(typeof reducer!=="function"){

throw new TypeError("Expected the reducer to be a function ")

}

//state存放状态 listener

存放事件池

let state,

isdispatch =false;

listeners = [];

//获取状态

getState(){

//优化一:把返回的信息进行深克隆,这样读取到的状态信息,不能直接基于对象.xx修改了

returncloneDeep(state)

}

//向事件池中追加方法

function subscribe(func){

if(typeof!=="function"){

throw new Error('Expectted the listener to be a function ')

}

//优化二

if(!listeners.includes(func)){

listeners = listeners.push(func);

}

returnfunctionunsubscribe(){

listeners.filter(item=>{

item!==function

})

}

}

//派发任务

function dispatch(action){

if(func===null||typeof action!=="object"){

throw new Error(

'Action must be plain objects.'+'Use custom middleware for async actions'

)

}

if(typeof action === 'undefined'){

throw new Error(

'Action may not have an undefined 'type' property'+'have you misspelled a constant?'

)

}

//优化三 防止在reducer中修改状态,不用用户自己手动克隆state,这里可以深克隆一下

let preState = state;

state = reducer(state,action);

//优化四 深比较 没有修改则不通知listeners中的方法执行

if(!compareDeep(preState,state){

listeners.forEach(item=>{

item();

})

}

}

//默认创建store 就执行一次dispatch 目的是给状态赋初始值

dispatch({

//不能和后期用户的action.type冲突

type:Symbol('INIT')

})

return {

setState,

subscribe,

dispatch

}

}

//优化四 深比较

export compareDeep(val1,val2){

lettype1 = typeof val1,

type2 = typeof val2;

if(type1===null&& type2===null){

returntrue

}

if(type1==="function"&&type2==="function"){

return val1.toString === val2.toString

}

if(type1==="object"&&type2==="object"){

let ct1 = val1.costructor,

ct2 = val2.constructor;

if((ct1===RegExp&&ct1===RegExp)||(ct2===Date&&ct2===Date)){

return val1.toString() === val2.toString()

}

let key1 = Object.keys(val1),

key2 = Object.keys(val2);

if(key1.length===key2.length){

key1.forEach(item=>{

let value1=val1[item],

value2=val2[item];

let res = compareDeep(value1,value2);

if(!res) return res

})

}

returnfalse;

}

//基本数据类型 直接基于三个等于号比较即可

return val1===val2

}

React-redux

React-redux是React基于Redux封装的状态管理库,基于Redux,它做了以下三个大事情:

  • 提供Provider祖先组件,把store仓库放置到上下文中供子组件调用
  • 提供connect方法,将状态通过属性的方式挂载到子组件上。把action-creator返回的对象类型转换为dispatch派发格式,并通过属性挂载到子组件上。
  • 返回的是代理组件(也是一个函数)把当前需要代理的组件作为参数放到返回的函数中即可,会帮我们给redux容器中的事件池中添加一个“公共状态改变能够重新渲染的事件方法。

思维导图:

React-redux部分源码

import React from 'redux';

import PropTypes from 'prop-types';

const ThemeContext = React. creatContext();

export class Provider extends React.Component{

static propTypes = {

store:PropTypes.object.isRequired

};

render(){

<ThemeContent value={

{

store:this.props.store

}

}>

//真实要渲染的组件拿过来渲染

{this.props.children}

</ThemeContent>

}

}

exportfunction connect(mapStateToProps,mapDispatchToProps){

//初始化参数

if(typeof mapStateToProps!=="function"){

mapStateToProps = state=>{

return{}

}

}

if(typeof mapDispatchToProps!=="function"){

if(mapDispatchToProps!==null&& typeof mapDispatchToProps==='object'){

let action = mapDispatchToProps;

mapDispatchToProps = dispatch=>{

let obj = {};

Object.keys(action).forEach(item=>{

obj[item] = (...args)=>{

dispatch(action[item](...args))

}

})

return obj;

}

}

mapDispatchToProps = dispatch=>{

return{}

}

}

returnfunction connectHOC(component){

return class proxy texends React.Component{

static contextType = ThemeContext;

render(){

return <component/>;

}

queryPros=()=>{

let { store } = this.conext,

state = store.getState(),

dispatch = store.dispatch;

return {

...mapStateToProps(state);

...mapDispatchToProps(dispatch)

}

}

componentDidMount(){

this.context.store.subscribe(()=>{

this.forceUpdate();

})

}

}

}

}

结合使用中间件

总结

  • 掌握Redux原理
  • 掌握React-redux运行原理
  • 配合使用中间件

以上是 彻底搞懂React-redux 的全部内容, 来源链接: utcz.com/a/27901.html

回到顶部