深入理解Redux之手写React-Redux
React-Redux主要由两部分组成,一是Provider(提供者),顾名思义作用就是提供状态数据。
另一部分是connect函数,它的作用是把UI组件和状态数据“连接”起来,实现了Model和View的分离,也就是UI组件并不直接管理状态数据,而是只负责界面的展示。
通过connect函数可以获得一个容器组件的创建器,进而创建出容器组件,而容器组件又包含了UI组件,由于容器组件是可以获取到状态数据的,获取到之后再传给UI组件就可以实现UI组件和状态数据的连接。
下面我们先来实现第一部分——Provider。
React-Redux库作用相当于是简化React对Redux的操作(因为Redux是独立于React的库,甚至也可以配合Vue.js等使用),因此React-Redux中的Provider并不直接拥有状态数据,
状态数据是在Redux中的。即Provider需要接收Redux中状态数据所在的store模块,才能获取到状态数据。如下:
<Provider store={store}>
<App/>
</Provider>
我们刚才说了容器组件需要获取状态数据,而Provider是状态数据的提供者,因此Provider需要将状态数据传给容器组件。Provider的实现非常简单,如下。
export class Provider extends React.Component {
static propTypes = {
store: PropTypes.object.isRequired // 声明接收Redux的store模块
}
// 声明要传给子组件(即容器组件)的数据名称(key)和数据类型
static childContextTypes = {
store: PropTypes.object
}
/* 指定上面的key对应的value */
getChildContext () {
return {
store: this.props.store
}
}
render() {
// 渲染<Provider>的所有子组件,在本例中就是<App/>
return this.props.children
}
}
接下来实现connect函数,我们刚才说了connect会产生一个包装了UI组件的容器组件的创建器。而UI组件一方面负责界面的显示(读取状态数据),另一方面又要和用户交互,如监听按钮的点击事件,并执行某些操作(修改状态数据)。
因此UI组件需要拥有两类属性,一类我们叫做stateProps,即状态数据,UI组件会将状态数据渲染到界面上。另一类叫dispatchProps(即更新状态数据的方法),dispatch是redux中的概念,可以通过dispatch函数分发一个action(执行某个动作,进而修改状态数据)。
UI组件可以调用dispatchProps中的方法去间接地修改状态数据。
由于容器组件接收的是store,而store包含的是Redux全量的状态数据,而某个UI组件可能只需要整个应用中部分的状态数据,因此需要一个名为mapStateToProps的函数指定该UI组件需要哪些状态数据。
例如mapStateToProps=state=>({user:state.user}),这个函数就表明了该UI组件只需要状态数据中的user。
同理,在Redux中有actions的概念,它包含了所有的操作类型,而某个UI组件可能也只需要做一部分操作,因此需要一个名为mapDispatchToProps的对象指定该UI组件需要哪些操作类型。
mapDispatchToProps一般是如下格式(①)
格式①:
{
key1: actionCreator1,
key2: actionCreator2
}
其中key是操作的名称,而后面的actionCreator是一个action的创建器,可以调用创建器产生action,进而通过dispatch方法分发该action。
我们最终要想获得dispatchProps,需要将其转换成如下这样的格式(②)。因为action的内容可能是变化的,比如我们要更新状态数据里面的user,需要产生一个对应的例如"updateUser"这样的action,显然我们在action中需要携带用户信息,不然怎么更新呢。因此
actionCreator是可以接收参数的,根据参数创建一个action。
格式②:
{
key1:(...arguments)=>{
dispatch(actionCreator1(...arguments))
},
key2:(...arguments)=>{
dispatch(actionCreator2(...arguments))
}
}
好了,准备知识都已经介绍完了,下面可以开始编写connect函数啦。
export function connect(mapStateToProps, mapDispatchToProps) {
// 接收两个参数,根据参数构造出UI组件所需的stateProps(状态数据)和dispatchProps(更新状态数据的方法)
//connect函数的返回值是一个ContainerComponentCreator,也就是容器组件的创建器,而我们说过容器组件会包装一个UI组件,因此创建器的方法参数是一个UI组件
return (UIComponent) => {
return class ContainerComponent extends React.Component {
// 容器组件需要声明接收Provider提供的store
static contextTypes = {
store: PropTypes.object
}
constructor (props, context) {
super(props)//调用父类构造器,不解释
// 得到Provider传过来的store
const store = context.store
// 构造状态数据
const stateProps = mapStateToProps(store.getState())
// 将状态数据作为容器的state(因为状态改变意味着我们的UI组件需要随之变化,而state的改变正好会使得容器组件重新渲染)
this.state = {...stateProps}
//构造dispatchProps(更新状态数据的方法),这段不解释,请对照上面的格式①和格式②,很容易看出这段代码做了什么
const dispatchProps = Object.keys(mapDispatchToProps).reduce((pre, key) => {
const actionCreator = mapDispatchToProps[key]
pre[key] = (...args) => store.dispatch(actionCreator(...args))
return pre
}, {})
// 保存到组件上
this.dispatchProps = dispatchProps
// 绑定redux状态变化的监听
store.subscribe(() => { // 状态变化的回调
// 更新容器组件的状态,使容器组件重新渲染,进而导致UI组件的更新
this.setState({...mapStateToProps(store.getState())})
})
}
render () {
// 渲染UI组件,并把UI组件所需的stateProps(状态数据)和dispatchProps(更新状态数据的方法)传入
return <UIComponent {...this.state} {...this.dispatchProps}/>
}
}
}
}
深入理解Redux之手写React-Redux的更多相关文章
- 手写React的Fiber架构,深入理解其原理
熟悉React的朋友都知道,React支持jsx语法,我们可以直接将HTML代码写到JS中间,然后渲染到页面上,我们写的HTML如果有更新的话,React还有虚拟DOM的对比,只更新变化的部分,而不重 ...
- JDK动态代理深入理解分析并手写简易JDK动态代理(下)
原文同步发表至个人博客[夜月归途] 原文链接:http://www.guitu18.com/se/java/2019-01-05/27.html 作者:夜月归途 出处:http://www.guitu ...
- JDK动态代理深入理解分析并手写简易JDK动态代理(上)
原文同步发表至个人博客[夜月归途] 原文链接:http://www.guitu18.com/se/java/2019-01-03/27.html 作者:夜月归途 出处:http://www.guitu ...
- 手写一个Redux,深入理解其原理
Redux可是一个大名鼎鼎的库,很多地方都在用,我也用了几年了,今天这篇文章就是自己来实现一个Redux,以便于深入理解他的原理.我们还是老套路,从基本的用法入手,然后自己实现一个Redux来替代源码 ...
- 【redux】详解react/redux的服务端渲染:页面性能与SEO
亟待解决的疑问 为什么服务端渲染首屏渲染快?(对比客户端首屏渲染) react客户端渲染的一大痛点就是首屏渲染速度慢问题,因为react是一个单页面应用,大多数的资源需要在首次渲染前就加载 ...
- React+Redux学习笔记:React+Redux简易开发步骤
前言 React+Redux 分为两部分: UI组件:即React组件,也叫用户自定义UI组件,用于渲染DOM 容器组件:即Redux逻辑,处理数据和业务逻辑,支持所有Redux API,参考之前的文 ...
- python-积卷神经网络全面理解-tensorflow实现手写数字识别
首先,关于神经网络,其实是一个结合很多知识点的一个算法,关于cnn(积卷神经网络)大家需要了解: 下面给出我之前总结的这两个知识点(基于吴恩达的机器学习) 代价函数: 代价函数 代价函数(Cost F ...
- React深入 - 手写redux api
简介: 手写实现redux基础api createStore( )和store相关方法 api回顾: createStore(reducer, [preloadedState], enhancer) ...
- 手写 redux 和 react-redux
1.手写 redux redux.js /** * 手写 redux */ export function createStore(reducer) { // 当前状态 let currentStat ...
随机推荐
- load加载层
//eg1 var index = layer.load(); //eg2 var index = layer.load(1); //换了种风格 //eg3 var index = layer.loa ...
- 【sed】进阶
sed的基本用法已能满足大多数需求,但当需要时,知道这些高级特效的存在及如何使用将提供莫大的帮助! 1. 多行命令 sed编辑器提供三个用于处理多行文本的特殊命令: N:将数据 ...
- 使用UltraISO制作linux系统安装u盘启动盘
1.首先打开UltraISO软件,尽量下载最新版的,小编曾用某个旧版的UltraISO,制作的安装盘,不能不能识别磁盘,安装失败! 2.点击工具栏中的第二个打开镜像文件工具,如图红色方框标志按钮,然后 ...
- mysql zip方式安装
下载zip文件解压到安装目录,此时是没有data文件夹和my.ini文件的. 1.首先自己新建my.ini,内容如下: [client] port=3306 default-character-set ...
- 【VMWare】虚拟机启动遇到黑屏,在命令行窗口输入netsh winsock reset并不管用 重新启动客户机就好了
现象:虚拟机启动后是莫名其妙的黑屏,而且它上面安装的MySql也无法访问了. 处置:上网百度方案,看到大多数网文推荐:“以管理员身份打开cmd,输入netsh winsock reset,然后重启机器 ...
- java常用的正则表达式的工具类
import com.google.common.base.Strings; import java.util.regex.Matcher;import java.util.regex.Pattern ...
- Java相关框架概念以及思想
1.什么是IoC Ioc—Inversion of Control,即“控制反转”,是一种思想, 一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合.更优良的程序. 高内聚低耦合的设计能够让构 ...
- Android云端APP
使用HbuilderX打包APP 首先创建一个 5+APP+使用MUI项目 <!DOCTYPE html> <html> <head> <meta chars ...
- js-jsTree
依赖:jquery.jsjstree.js//cdnjs.cloudflare.com/ajax/libs/jstree/3.3.3/themes/default/style.min.css 备注:绑 ...
- ECS Samples概述
本文档介绍了Unity 面向数据的技术堆栈(DOTS)的三个主要方面:实体包,Unity C#作业系统和Unity Burst编译器所涵盖的Unity实体 - 组件系统(ECS).由于实体是DOTS中 ...