本文原文链接

在之前的一篇文章中已讲过redux 原理解析,我将redux返回的store对象挂载在window中,不是太懂的同学可以看看之前的redux 原理解析。

const reducer = combineReducers({home: homeNumber,number: addNumber
})
const store = createStore(reducer)
window.$reduxStore = store// 使用
window.$reduxStore.dispatch(action);
let { state } = window.$reduxStore.getState()

但在平时的开发中,一般是将redux+react-redux+react配合使用,那么,下面就一起来看看react-redux中的常见方法,它具体做了什么。【下面是以最新版本react-redux@7.1.3库解析】(下面的源码部分省略)

#Provider函数

react-redux提供了<Provider />组件用来挂载redux返回的store对象,同时将整个应用作为Provider的子组件。

ReactDOM.render( <Provider store={store}> <App /> </Provider>,   rootElement )

下面看看<Provider />组件做了什么:

function Provider({ store, context, children }) {// 依赖项store变化触发,返回store和subscriptionconst contextValue = useMemo(() => {// 订阅监听Subscription函数,下面会专门说到const subscription = new Subscription(store)subscription.onStateChange = subscription.notifyNestedSubsreturn {store,subscription}}, [store])//...// ReactReduxContext = React.createContext(null)const Context = context || ReactReduxContextreturn <Context.Provider value={contextValue}>{children}</Context.Provider>
}
// 源码地址:https://github.com/reduxjs/react-redux/blob/master/src/components/Provider.js#L6

Provider接收三个参数,store参数接收store对象,context参数接收上下文对象,children参数接收ReactElement元素; 在原应用组件上包裹一层,使原来整个应用成为Provider的子组件,Context.Provider API:只有当 Provider 的 value 值发生变化时,它内部的所有消费组件都会重新渲染

contextValue挂载在Provider上,contextValue包含store对象和订阅发布subscription对象,以备connect组件使用获取。Subscription主要负责connect、Provider组件的更新,属于核心内容,这些将在下面讲到。

#connect函数

connect的常见使用示例:

return connect(mapStateToProps, mapDispatchToProps)(Component)

connect函数就是一个高阶组件,将以上的参数传入函数,返回一个新的组件,主要就是将statedispatch等属性挂载Component的props上。

import hoistStatics from 'hoist-non-react-statics'
import { ReactReduxContext } from './Context';// 核心函数 return组件
function ConnectFunction (props) {//  ...// 判断props 是否存在store & getState & dispatch,一般都为falsevar didStoreComeFromProps = Boolean(props.store) && Boolean(props.store.getState) && Boolean(props.store.dispatch);// 获取Provider组件挂载的contextValuevar ContextToUse = useMemo(function () {return propsContext &&propsContext.Consumer &&isContextConsumer(<propsContext.Consumer />)? propsContext: Context})// contextValue = { store, subscription }var contextValue = useContext(ContextToUse)//  ...// 依赖返回 contextValuevar overriddenContextValue = useMemo(function () {if (didStoreComeFromProps) {return contextValue}return {...contextValue,subscription}}, [didStoreComeFromProps, contextValue, subscription]);//  ...// actualChildProps == props,上挂载了```state```和```dispatch```等属性const renderedWrappedComponent = useMemo(() => <WrappedComponent {...actualChildProps} ref={forwardedRef} />,[forwardedRef, WrappedComponent, actualChildProps])// 返回渲染ReactElementvar renderedChild = useMemo(function () {// 判断是否存在mapStateToProps函数if (shouldHandleStateChanges) {return (<ContextToUse.Provider value={overriddenContextValue}>{renderedWrappedComponent}</ContextToUse.Provider>)}// renderedWrappedComponent 渲染容器组件return renderedWrappedComponent}, [ContextToUse, renderedWrappedComponent, overriddenContextValue]);return renderedChild;
}
//  ...
// 与Object.assign类似操作
return hoistStatics(ConnectFunction, WrappedComponent)

hoistStatics函数的作用就是类似于Object.assign,可以这样理解hoistStatics(targetComponent, sourceComponent),hoist-non-react-statics库。上面代码中ConnectFunction是核心函数,虽然中间部分代码省略,不过留下的都是精华。

ConnectFunction函数中,通过hooks useContext获取Provider组件的contextValue对象;renderedWrappedComponent将actualChildProps作为props传入,actualChildProps是已经处理过的props属性,上面已经挂载了dispatch函数和state状态等属性;而renderedChild组件,其实connect函数最后返回的实际内容。(中间部分代码省略了源码链接跳转)

以上就是Provice组件和connect组件初次调用时,所经过的实际代码,当然在其中有一些删减,不过基本都有说到。

当dispatch被调用时,会发生什么呢?上面部分完全没有说到,下面我们就来看看当dispatch(action)调用后,react-redux内部,是如何更新connect组件。

#connect如何更新?

当在React应用中调用dispatch函数时,redux中实际调用的就是reducer函数,同时返回新的state。那么redux-react中的connect组件如何更新呢,下面我们来一起看看更新的流程:

dispatch(action)

下面内容不是精读代码,只是聊一下基本的流程

#初始化

Provider组件被调用注册时,订阅更新Subscription函数被注册:

const subscription = new Subscription(store)

在redux-react中,订阅发布函数Subscription是其中的核心函数(订阅发布模式是其核心),它有效的保证connect组件的更新渲染。store作为参数传入到Subscription构造函数内部,作用就是Subscription内部使用

#订阅

return connect(mapStateToProps, mapDispatchToProps)(Component)// react-redux中,checkForUpdates函数,负责更新connect组件
subscription.onStateChange = checkForUpdates// redux保存触发 通知函数
store.subscribe(subscription.notifyNestedSubs);// react-redux保存 更新函数
subscription.listeners.subscribe(subscription.onStateChange)

在connect组件被使用时,react-redux中的subscription对象,会将connect组件的checkForUpdates更新函数作为参数,传入保存在subscription的订阅数组next中;同时,redux也会发生相同的操作【在react-redux中也有使用到redux中方法】。(代码为简化版)

// redux中 subscribe函数
let nextListeners = []
subscribe(listener) {// ... nextListeners.push(listener)
}
// react-redux中 subscribe函数
let next = []
subscribe(listener) {// ... next.push(listener)
}

checkForUpdates函数负责connect组件的内部的状态更新。

notifyNestedSubs函数是作用是触发react-redux中的subscription对象的更新函数,而它被保存在nextListeners数组中,是为了当redux的dispatch函数被触发时,调用notifyNestedSubs通知函数,进而触发react-redux的connect组件的checkForUpdates更新函数。

react-redux:checkForUpdates 函数源码

react-redux:Subscription 函数源码

#发布(更新)

dispatch(action)发起触发操作后,当然是触发store中dispatch函数了,修改store中state的值,更新遍历redux的nextListeners订阅数组,触发通知函数notifyNestedSubs调用;同时,这会导致react-redux中的next数组,被触发遍历调用。两个库基本都是下面的代码

let next = listeners;​
for (let i = 0; i < listeners.length; i++) {listeners[i]()
}

以上细节可能有所省略,但基本就是先订阅,将更新函数保存进入订阅数组,然后当dispatch函数被调用时,遍历调用订阅数组,完成connect组件的更新。

在最新的react-redxu库中 ,有大量的React Hooks出现,中间我木有过多的说明,有兴趣可以自行研究。(高阶组件、React Hooks、订阅发布模式)

ps: 微信公众号:Yopai,有兴趣的可以关注,每周不定期更新。不断分享,不断进步

react 判断地址是否有效_继续,react-redux原理解析相关推荐

  1. react性能监控根据工具_高性能React:3个新工具可加快您的应用程序

    react性能监控根据工具 by Ben Edelstein 通过本·爱德斯坦 高性能React:3个新工具可加快您的应用程序 (High Performance React: 3 New Tools ...

  2. react中使用构建缓存_使用React构建Tesla的电池范围计算器(第1部分)

    react中使用构建缓存 by Matthew Choi 由Matthew Choi 使用React构建Tesla的电池范围计算器(第1部分) (Building Tesla's Battery Ra ...

  3. react根据中文获取拼音_解决 React 中的 input 输入框在中文输入法下的 bug

    以下会涉及到的技术点:react mobx compositionstart compositionupdate compositionend 问题描述 在使用 input 时,通常会对输入的内容做校 ...

  4. react 逆地理 高德地图_在react中使用原生的高德地图

    1.使用react-create-app创建一个新的react项目 2.修改index.html,添加以下script引用: 3.创建一个组件文件MapDemo.js,内容如下 import Reac ...

  5. react中使用构建缓存_使用React和Netlify从头开始构建电子商务网站

    react中使用构建缓存 In this step-by-step, 6-hour tutorial from Coding Addict, you will learn to build an e- ...

  6. native react 变颜色 点击_在React Native中按下更改按钮样式(Change button style on press in React Native)...

    问 题 我希望我的应用中按钮的样式在按下时更改.最好的方法是什么? 解决方案 使用 touchablehighlight . 这里有一个例子: 'use strict'; import react,{ ...

  7. react 使用 leaflet 百度地图_【React】react项目中应用百度地图添加起始点绘制路线...

    如图:项目中百度地图的应用添加起始点.终点并绘制路线 在展示代码的时候首先展示一下后台返回给我的接口 { 其中position_list参数代表的是用户的行驶点, area参数代表的是服务区的坐标点, ...

  8. react 将token充入_【React全家桶入门之十】登录与身份认证

    细致想想,我们的后台系统还没有一个登录功能,太不靠谱,赶紧把防盗门安上! SPA的鉴权方式和传统的web应用不同:因为页面的渲染不再依赖服务端,与服务端的交互都通过接口来完毕,而REASTful风格的 ...

  9. react 实现滚动加载_在React中实现平滑滚动

    react 实现滚动加载 Smooth Scrolling, dont know what it is? Well, instead of clicking on a button and being ...

最新文章

  1. 智能车竞赛技术报告 | 智能车视觉 - 青岛工学院 - 青工战斗
  2. 剑指offer五:两个栈实现一个队列
  3. 【AutoML】如何选择最合适的数据增强操作
  4. 有关logistic(sigmoid)函数回归
  5. Hadoop1.2.1集群安装二
  6. 数据结构之基于顺序表的插入排序
  7. Centos下安装配置WordPress与nginx教程
  8. SQL:ISNULL
  9. DOM操作案例之--全选与反选
  10. 设置网页右键点击,并阻止右键点击默认事件
  11. Matlab学习记录 1
  12. 字节跳动在京斥资50亿购置新大楼:数千名员工已入驻
  13. 英文站变现赚美金的7种方式
  14. 对JAVA常用计算总结_JAVA开根号,多次方,对数指数等的计算,只提供示例代码具体参考JDK类Math的API
  15. 《LeetCode刷题》—121. 买卖股票的最佳时机
  16. python导入excel散点图_Python 写excel文件并插入散点图
  17. 慎用chrome密码记住功能
  18. 汇哲培训——IT审计师轻叩中国大门--小球撬动大球
  19. 《中华红》一个会作词的程序员
  20. Java实现简易的界面通讯录

热门文章

  1. Delphi之面向对象的界面复用技术
  2. 数字人民币明确不采用区块链技术,对数字货币投资须保持警惕
  3. mvc:interceptor 不起作用的一个解决方法
  4. Unity3d Time的使用
  5. pom.xml配置文件中所有标签及作用简单描述
  6. 【译】Everything You Need to Know About Decentralized AI
  7. 【译】Writing a Simple Linux Kernel Module
  8. RNN-循环神经网络-02Tensorflow中的实现
  9. 反调试检测之一TracerPid
  10. Android apk动态加载机制的研究