阅读react-redux源码(二) - createConnect、match函数的实现

  • 阅读react-redux源码 - 零
  • 阅读react-redux源码 - 一
  • 阅读react-redux源码(二) - createConnect、match函数的实现

上一节看了Provider组件的实现,主要做的事情就是通过Context透传了来自redux的store和监听store变化的事件对象Subscription的实例。

本节会深入到connect组件的内部查看实现方式,整个connect组件的实现相对复杂,并且巧妙。

通过入口文件可以知道connect组件是/src/connect/connect.js的默认导出。文件内容如下:

import connectAdvanced from '../components/connectAdvanced'
import shallowEqual from '../utils/shallowEqual'
import defaultMapDispatchToPropsFactories from './mapDispatchToProps'
import defaultMapStateToPropsFactories from './mapStateToProps'
import defaultMergePropsFactories from './mergeProps'
import defaultSelectorFactory from './selectorFactory'/*connect is a facade over connectAdvanced. It turns its args into a compatibleselectorFactory, which has the signature:(dispatch, options) => (nextState, nextOwnProps) => nextFinalPropsconnect passes its args to connectAdvanced as options, which will in turn pass them toselectorFactory each time a Connect component instance is instantiated or hot reloaded.selectorFactory returns a final props selector from its mapStateToProps,mapStateToPropsFactories, mapDispatchToProps, mapDispatchToPropsFactories, mergeProps,mergePropsFactories, and pure args.The resulting final props selector is called by the Connect component instance wheneverit receives new props or store state.*/
function match(arg, factories, name) {for (let i = factories.length - 1; i >= 0; i--) {const result = factories[i](arg)if (result) return result}return (dispatch, options) => {throw new Error(`Invalid value of type ${typeof arg} for ${name} argument when connecting component ${options.wrappedComponentName}.`)}
}function strictEqual(a, b) {return a === b
}// createConnect with default args builds the 'official' connect behavior. Calling it with
// different options opens up some testing and extensibility scenarios
export function createConnect({connectHOC = connectAdvanced,mapStateToPropsFactories = defaultMapStateToPropsFactories,mapDispatchToPropsFactories = defaultMapDispatchToPropsFactories,mergePropsFactories = defaultMergePropsFactories,selectorFactory = defaultSelectorFactory
} = {}) {return function connect(mapStateToProps,mapDispatchToProps,mergeProps,{pure = true,areStatesEqual = strictEqual,areOwnPropsEqual = shallowEqual,areStatePropsEqual = shallowEqual,areMergedPropsEqual = shallowEqual,...extraOptions} = {}) {const initMapStateToProps = match(mapStateToProps,mapStateToPropsFactories,'mapStateToProps')const initMapDispatchToProps = match(mapDispatchToProps,mapDispatchToPropsFactories,'mapDispatchToProps')const initMergeProps = match(mergeProps, mergePropsFactories, 'mergeProps')return connectHOC(selectorFactory, { // used in error messagesmethodName: 'connect',// used to compute Connect's displayName from the wrapped component's displayName.getDisplayName: name => `Connect(${name})`,// if mapStateToProps is falsy, the Connect component doesn't subscribe to store state changesshouldHandleStateChanges: Boolean(mapStateToProps),// passed through to selectorFactoryinitMapStateToProps,initMapDispatchToProps,initMergeProps,pure,areStatesEqual,areOwnPropsEqual,areStatePropsEqual,areMergedPropsEqual,// any extra options args can override defaults of connect or connectAdvanced...extraOptions})}
}export default /*#__PURE__*/ createConnect()

createConnect

首先看看createConnect,关于函数如果有注释先看注释然后主要看函数名,一个好的函数名会表明这个函数是做什么的。再看函数的入参和函数的出参,最后可以看函数的实现方式。

export function createConnect({connectHOC = connectAdvanced,mapStateToPropsFactories = defaultMapStateToPropsFactories,mapDispatchToPropsFactories = defaultMapDispatchToPropsFactories,mergePropsFactories = defaultMergePropsFactories,selectorFactory = defaultSelectorFactory
} = {}) {return function connect(mapStateToProps,mapDispatchToProps,mergeProps,{pure = true,areStatesEqual = strictEqual,areOwnPropsEqual = shallowEqual,areStatePropsEqual = shallowEqual,areMergedPropsEqual = shallowEqual,...extraOptions} = {}) {}
}

首先这个函数定义参数的形式有点奇怪,function name({a = 1, b = 2} = {})这种形式。这其实是JS中的命名参数的写法,和Python、Dart之类的语言中提供的命名参数特性类似。入参的赋值和名字有关,而不是位置。

而入参分别是connectHOC还有剩下来的几个factory,分别是生产mapStateToProps的工厂、生产mapDispathToProps的工厂,生产mergeProps的工厂和生产选择器的工厂。

后面createConnect函数会返回connect函数,而这个connect函数就是连接组件用到的组件。

在底部会执行createConnect方法则会得到该方法返回的connect函数,在组件中通过connect函数可以连接到顶层Provider提供的store和Subscribtion实例。

connect函数

return function connect(mapStateToProps,mapDispatchToProps,mergeProps,{pure = true,areStatesEqual = strictEqual,areOwnPropsEqual = shallowEqual,areStatePropsEqual = shallowEqual,areMergedPropsEqual = shallowEqual,...extraOptions} = {}) {const initMapStateToProps = match(mapStateToProps,mapStateToPropsFactories,'mapStateToProps')const initMapDispatchToProps = match(mapDispatchToProps,mapDispatchToPropsFactories,'mapDispatchToProps')const initMergeProps = match(mergeProps, mergePropsFactories, 'mergeProps')return connectHOC(selectorFactory, {// used in error messagesmethodName: 'connect',// used to compute Connect's displayName from the wrapped component's displayName.getDisplayName: name => `Connect(${name})`,// if mapStateToProps is falsy, the Connect component doesn't subscribe to store state changesshouldHandleStateChanges: Boolean(mapStateToProps),// passed through to selectorFactoryinitMapStateToProps,initMapDispatchToProps,initMergeProps,pure,areStatesEqual,areOwnPropsEqual,areStatePropsEqual,areMergedPropsEqual,// any extra options args can override defaults of connect or connectAdvanced...extraOptions})}

connect函数就是我们用于连接store的函数。connect函数的入参分别是 mapStateToPropsmapDispatchToPropsmergeProps和一个配置对象。

首先看下入参的配置对象:

{pure = true,areStatesEqual = strictEqual,areOwnPropsEqual = shallowEqual,areStatePropsEqual = shallowEqual,areMergedPropsEqual = shallowEqual,...extraOptions
} = {}

配置对象定义了用于对比数据的函数,分别是对比store中的state,对比被包裹组件自身的props,对比被组件选中的store中的state,对比被包裹组件自身的props和来自store的state被选中的state。

这里要注意,我们知道一个连接到store的组件的props会有两个来源,一个是store,包括store中的state和dispatch。还有一个是父组件传递给组件的props。 而要做到性能最优则是接收到新的值时对这些值分别对比,如果没有改变则不需要更新组件,以优化组件性能。

const initMapStateToProps = match(mapStateToProps,mapStateToPropsFactories,'mapStateToProps'
)
const initMapDispatchToProps = match(mapDispatchToProps,mapDispatchToPropsFactories,'mapDispatchToProps'
)
const initMergeProps = match(mergeProps, mergePropsFactories, 'mergeProps')

这段代码统一处理了三个工厂函数生成目标函数的过程。

function match(arg, factories, name) {for (let i = factories.length - 1; i >= 0; i--) {const result = factories[i](arg)if (result) return result}return (dispatch, options) => {throw new Error(`Invalid value of type ${typeof arg} for ${name} argument when connecting component ${options.wrappedComponentName}.`)}
}

factories是数组,遍历这个数组,找到一个真的返回值,返回出去,否则返回一个会抛出错误的方法。这是责任链模式,factories是一个链,数组的每一项只处理自身的情况,如果匹配则返回,否则返回undefined通知match继续遍历链。

factories对应的数据结构式[() => (fn || undefined), () => (fn || undefined), ...]

注意:match从右往左遍历factories数组。

整理好相关入参,全部传递给connectHOC,这个高阶组件是整个connect的核心,如何订阅store更新,如何防止store的更新引起不必要的渲染,如何处理ref的获取,如何使用通过props传入的context和store,如何透传父组件传入的props。这些都会在connect中处理。

  • 阅读react-redux源码 - 零
  • 阅读react-redux源码 - 一
  • 阅读react-redux源码(二) - createConnect、match函数的实现

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/362007.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一个罐子统治一切:Apache TomEE + Shrinkwrap == JavaEE引导

警告:我不是Spring Boot的专家。 我发现很多事情对此非常有趣,并且当然可以真正改善您的日常工作。 而且,我对Spring Boot没有任何反对,也没有开发或使用它的人。 但是我认为社区高估了该产品。 一年前,我开始收到很多…

iview-admin框架运行步骤

第一步: 前往github下载整个iview-admin框架的全部源码 github地址: https://github.com/iview/iview-admin 第二步: 点击Clone or download绿色按钮。下载整个压缩包 第三步: 解压至D盘,在根目录中按 1、前往github下…

阅读react-redux源码(三) - mapStateToPropsFactories、mapDispatchToPropsFactories和mergePropsFactories

阅读react-redux源码 - 零阅读react-redux源码 - 一阅读react-redux源码(二) - createConnect、match函数的实现阅读react-redux源码(三) - mapStateToPropsFactories、mapDispatchToPropsFactories和mergePropsFactories mapStateToPropsFactories import { wrapMapToPropsC…

Xcode 升级后,常常遇到的遇到的警告、错误,解决方法(转)

从sdk3.2.5升级到sdk 7.1中间废弃了很多的方法,还有一些逻辑关系更加严谨了。1,警告:“xoxoxoxo” is deprecated解决办法:查看xoxoxoxo的这个方法的文档,替换掉这个方法即可。2,警告:Declarat…

.net 垃圾回收学习[How To: Use CLR Profiler][翻译学习]【2】

http://msdn.microsoft.com/zh-cn/library/ms979205 注意:内容可能已经过期了。 注意:CLR Profiler最新版本:http://www.microsoft.com/download/en/details.aspx?id16273 Identifying Common Garbage Collection Issues 可以使用CLR Profil…

JavaOne 2014:会议与合同利益冲突

杜克街咖啡馆,工程师可以在街上进行走廊交谈 。 与签约不兼容 我的第11届JavaOne会议(2004年至2014年为11 10 1)非常出色。 值得参加此活动并结识社区中所有参与的人。 现在,这里是绅士的,但 。 除了经济上的明显优…

JQuery(三)-- AJAX的深入理解以及JQuery的使用

HTTP HTTP http: 超文本传输协议。特点: 简单、快速、灵活、无状态、无连接 URL: 统一资源定位符。 组成:协议名://主机IP:端口号/项目资源地址?传递参数的键值对#锚点 ①ip地址在同一个网段是唯一的。如果是在公…

阅读react-redux源码(四) - connectAdvanced、wrapWithConnect、ConnectFunction和checkForUpdates

阅读react-redux源码 - 零阅读react-redux源码 - 一阅读react-redux源码(二) - createConnect、match函数的实现阅读react-redux源码(三) - mapStateToPropsFactories、mapDispatchToPropsFactories和mergePropsFactories阅读react-redux源码(四) - connectAdvanced、wrapWithC…

(转)模拟鼠标/键盘

鼠标操作类 using System;namespace Edobnet.Net.Lib{/// <summary>/// Mouse 的摘要说明。/// </summary>public class Mouse{public Mouse(){//// TODO: 在此处添加构造函数逻辑//}internal const byte SM_MOUSEPRESENT 19;internal const byte SM_CMOUSEBUTTON…

c++ 返回 char*

一段在C里经常犯错误的代码 一个类&#xff1a; class C{public:C(){}~C(){}public:string a;string funa(){string tmp "1234";return tmp;}};外部调用类C并使用其成员&#xff1a; C classc;char *test1 classc.a.c_str();printf("%s\n", test1);上述正…

JSF的工作方式和调试方式–可以使用polyglot吗?

JSF不是我们通常认为的那样。 这也是一个调试起来可能有些棘手的框架&#xff0c;尤其是在初次遇到时。 在这篇文章中&#xff0c;让我们继续探讨为什么会出现这种情况&#xff0c;并提供一些JSF调试技术。 我们将讨论以下主题&#xff1a; JSF不是我们经常想到的 JSF调试的难…

React组件实现越级传递属性

如果有这样一个结构&#xff1a;三级嵌套&#xff0c;分别是&#xff1a;一级父组件、二级子组件、三级孙子组件&#xff0c;且前者包含后者&#xff0c;结构如图&#xff1a; 如果把一个属性&#xff0c;比如color&#xff0c;从一级传递给三级&#xff0c;一般做法是使用prop…

尝试Office 2003 VSTO的开发、部署

背景&#xff1a;一年前&#xff0c;某项目需要使用到Excel进行数据录入&#xff0c;考虑到很多用户还是使用XPOffice 2003&#xff0c;所以开发的时候直接使用Excel 2003版本进行VBA开发。也许很多人都会说&#xff0c;Win10都出了&#xff0c;微软的Office都要免费了&#xf…

阅读react-redux源码(五) - connectAdvanced中store改变的事件转发、ref的处理和pure模式的处理

阅读react-redux源码 - 零阅读react-redux源码 - 一阅读react-redux源码(二) - createConnect、match函数的实现阅读react-redux源码(三) - mapStateToPropsFactories、mapDispatchToPropsFactories和mergePropsFactories阅读react-redux源码(四) - connectAdvanced、wrapWithC…

Servlet编程API

一、基本的servlet APIJavaEE关于Servlet的API主要有两个包&#xff1a;javax.servlet和javax.servlet.http。前者主要提供了Web容器能够使用的servlet基本类和接口&#xff0c;后者主要包括和HTTP协议相关的servlet类和接口。对servlet的编程&#xff0c;主要是根据需要&#…

初级开发人员在编写单元测试时常犯的错误

自从我编写第一个单元测试以来已经有10年了。 从那时起&#xff0c;我不记得我已经编写了成千上万的单元测试。 老实说&#xff0c;我在源代码和测试代码之间没有任何区别。 对我来说是同一回事。 测试代码是源代码的一部分。 在过去的3-4年中&#xff0c;我与多个开发团队合作…

OpenDaylight开发hello-world项目之开发工具安装

OpenDaylight开发hello-world项目之开发环境搭建 OpenDaylight开发hello-world项目之开发工具安装 OpenDaylight开发hello-world项目之代码框架搭建 在ODL开发之前&#xff0c;要安装好开发环境。ODL使用java语言开发&#xff0c;所以要安装好java。ODL的代码框架是有maven这个…

Google Chrome 扩展程序开发

根据公司的规定&#xff0c;每月八小时&#xff0c;弹性工作制。所以大家平时来的不太准时&#xff0c;如果有事&#xff0c;下班也就早些回去了。所以一个月下来工作时间可能不够&#xff0c;但是公司的考勤日历是这样的&#xff1a; 除了请假和法定节假日外&#xff0c;其他样…

阅读react-redux源码(六) - selectorFactory处理store更新

阅读react-redux源码 - 零阅读react-redux源码 - 一阅读react-redux源码(二) - createConnect、match函数的实现阅读react-redux源码(三) - mapStateToPropsFactories、mapDispatchToPropsFactories和mergePropsFactories阅读react-redux源码(四) - connectAdvanced、wrapWithC…

[Silverlight入门系列]使用MVVM模式(7):ViewModel的INotifyPropertyChanged接口实现

本文说说ViewModel的这个INotifyPropertyChanged接口可以用来做啥&#xff1f; 举例1&#xff1a;我有个TabControl&#xff0c;里面放了很多View&#xff0c;每个由ViewModel控制&#xff0c;我想是想TabSelectionChanged就打开相应的ViewModel&#xff0c;怎么做&#xff1f;…