React中的connect使用(Provider+Consumer例子 以及 contextType+this.context例子)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React中的connect使用(Provider+Consumer例子 以及 contextType+this.context例子)相关的知识,希望对你有一定的参考价值。
参考技术AReact16.x之后使用新的context
React.createContext()、Provider、Consumer
App.jsx
Son.jsx
grandson.jsx
思想:
React.createContext会生成对应的Provider,Consumer组件,
传递数据的是Provider,Provider通过value属性进行传递数据
接收数据的是Consumer,Consumer是一个函数,通过参数,得到传递的数据
如果子组件找不到父辈组件被Provider 包裹,createContext("默认值")生效
Provider可以多层嵌套,子组件取值从最近的开始
一个Provider 可以对应多个Consumer
App.js
context.js
son.js
grandson.js
曾经的循环引用错误
Cannot access \'AppContext\' before initialization
没定义context.js,造成了App.js中间接引用了孙子,孙子中引用了App.js中的export const commonContext = createContext();
思想:
跟组件通过Provider 的value 传递数值,消费的类组件,用static contextType = commonContext; 接受后,就可以使用this.context 获取Provider 的value值
React×Redux——react-redux库connect()方法与Provider组件
tip:有问题或者需要大厂内推的+我脉脉哦:丛培森 ٩( ‘ω’ )و
【本文源址:http://blog.csdn.net/q1056843325/article/details/54880804 转载请添加该地址】
在写Redux的时候我们就了解了
如果使用Redux的话配合React是最好的
Dan Abramov为此还特意封装了一个react-redux库来提供便利
#概念
一旦我们选择使用了这个react-redux库
那么我们的组件概念就要加以区分了
从现在起我们的组件分为展示组件和容器组件两种
(参考了通俗易懂的阮大神博客)
##展示组件
展示组件(presentational component)
也叫UI组件、纯组件
特点如下:
- 负责UI显示
- 无状态不使用this.state
- 数据来自this.props
- 不使用任何redux的API
展示组件其实就是把我们的普通组件的数据与逻辑抽离出来
##容器组件
容器组件(container component)
特点如下:
- 负责管理数据和业务逻辑
- 带有内部状态
- 使用redux的API
容器组件是由我们react-redux库的API通过展示组件生成的
##关系
从它们的名字也可以猜到,它们是内外关系
容器组件包裹着展示组件
##优势
说的再通俗一些
我们原来是将结构和逻辑都装在一个组件中
现在将这个组件继续拆成负责视图的组件和负责逻辑数据的组件
这样做有如下优点:
- 理解
- 数据与逻辑分开,更便于我们理解
- 分离
- 必须将标签拆分,可用性更强
- 重用
- 一个展示组件可以搭配不同容器组件
- 视图
- 展示组件可以放到单独页面中调整UI
下面我们来看一下react-redux库的核心
connect()方法与Provider组件
#connect
上面也说到了
我么的容器组件是由库API得到的
而这个函数就是connect
connect的意思就是连接展示组件与容器组件的意思
为了加以区分,我用Container表示容器组件,用Component表示展示组件
用法如下
import connect from 'react-redux';
const Container = connect()(Component);
结构就是这个样子
<Container>
<Component/>
</Container>
不过现在我们仅仅是通过展示组件生成了一个容器组件
并且将它们连接了起来
但是容器组件中并没有数据和逻辑
只是一具空壳,毫无意义
所以我们还需要向这个connect函数中传入两个参数
它接收两个值作为参数:(实际是四个,另外两个不常用暂时不讲)
- mapStateToProps(输入逻辑)
- 负责将通过state获得的数据映射到展示组件的this.props
- mapDispatchToProps(输出逻辑)
- 负责将用户操作转化为Action的功能函数映射到展示组件的this.props
名字就和reducer一样,只是官方的概念性叫法(不过还是蛮形象的)
使用的时候可以自定义名字(不过一定要语义化)
所以完整的用法应该是这样的
const Container = connect(
mapStateToProps,
mapDispatchToProps
)(Component);
但是此时mapStateToProps与mapDispatchToProps我们还没有定义
##mapStateToProps
mapStateToProps负责将state的数据映射到展示组件的this.props
它是一个函数,接收参数state对象
如果有必要的话,还可以使用第二个参数:容器组件的props属性
返回一个对象表示state到展示组件props的映射关系
const mapStateToProps = (state) =>
return
list: state.list
此时你会发现这个函数名有多合适
- 返回对象中的“值”——
state.list
- 表示我们要将state的list数组传递给内部的展示组件
- 返回对象中的“键”——
list
- 表示我们在展示组件中可以通过this.props.list来获取这个数组
但有时,我们不能这么轻松的就通过state的某个属性值获得要传递的数据
这时我们可以自定义一个处理函数返回要传递的数据
const mapStateToProps = (state) =>
return
list: handler(state.list, state.option);
比如说这里handler就是我们的处理函数
拿我上一篇文章的toDoList待办事项列表为例
这个handler大概是这样的
const handler = (list, option) =>
switch(option)
case "SHOW_ACTION":
return list.filter(...);
case "SHOW_CROSSED":
return list.filter(...);
...
default:
return list;
这个函数我没有写完整,相信大家应该都能看明白
通过判断option我来将list数组进行 “过滤”
函数返回后作为数据返回给展示组件
mapStateToProps会订阅store,state更新后,就会触发展示组件重绘
不过在connect( )函数中,我们可以省略mapStateToProps
如果这么做的话,store更新就不会触发展示组件重绘了
上面也说道了,除了state我们还可以使用容器组件的属性props
const mapStateToProps = (state, ownProps) =>
return
...
如果容器组件的props发生改变的话,同样会触发展示组件重绘
##mapDispatchToProps
mapDispatchToProps负责定义发送action的函数映射到展示组件的this.props
与它的兄弟不同,它既可以是函数也可以是对象
作为函数,它会得到store.dispatch作为参数
同样还有一个容器组件的props属性可以使用
返回值我不用说大家也能猜到
就是一个表示映射关系的对象
但是这里表示的是用户如何发出Action(比如触发事件)
const mapDispatchToProps = (state, ownProps) =>
return
onClick: () =>
dispatch(
type: 'SET_FILTER',
filter: ownProps.filter
)
- 返回对象中的“值”——
() => dispatch(...)
- 表示我们要传递给内部展示组件的函数(函数功能:dispatch一个action)
- 返回对象中的“键”——
onClick
- 表示我们在展示组件中可以通过this.props.onClick来获取这个函数
如果是作为对象的话,就更简单了
上面的写法和下面的等价
const mapDispatchToProps =
onClick: (filter) =>
type: 'SET_FILTER',
filter: filter
这个对象的值是一个函数,它被认为是一个Action Creator
函数的参数可以填入容器组件的props
返回的Action会由redux自动dispatch
#Provider
在完成了Container与Componet的连接
实现了Container的管理数据与业务逻辑之后还没完
还有问题
我们使用了mapStateToProps,它的参数是state
也就是说,他需要传入state
如果我们手动将state对象一层一层的传入容器组件
应用小还好说,大应用深层的组件简直累死了,绝对让你传到怀疑人生
好在,react-redux提供了Provider组件让我们省了不少功夫
它就相当于我们整体的容器组件(不过区别很大)
用法就是在我们根组件外部嵌套一层Provider,传入store
(使用全局的store有风险)
这样所以的子组件都可以开心地拿到state了
我们也省心了
render(
<Provider store=store>
<App/>
</Provider>,
document.getElementById('root')
);
内部的原理是:
Provider接受store作为其props,并声明为context的属性之一
子组件在声明了contextTypes之后可以通过this.context.store访问到store
#小实例
上一次介绍Redux的时候介绍了一个简单的计数器
这次我把那个代码拿过来改装一下
import React from 'react';
import Component from 'react'
import ReactDom from 'react-dom';
import createStore, combineReducers from 'redux';
import connect, Provider from 'react-redux';
首先定义单纯用来展示UI的展示组件
class Counter extends Component
render()
const value, reduceHandler, addHandler = this.props;
return (
<div>
<p>value</p>
<button onClick=reduceHandler>-</button>
<button onClick=addHandler>+</button>
</div>
)
;
然后定义映射函数,生成容器组件
const mapStateToProps = (state) =>
return
value: state.cnt
const mapDispatchToProps = (dispatch) =>
return
reduceHandler: () =>
dispatch(type: 'REDUCE');
,
addHandler: () =>
dispatch(type: 'ADD');
const APP = connect(mapStateToProps, mapDispatchToProps)(Counter);
Reducer稍微修改一下
const reducer = (state = cnt: 0, action) =>
switch (action.type)
case 'ADD':
return cnt: state.cnt + 1;
case 'REDUCE':
return cnt: state.cnt - 1;
default:
return state;
;
const store = createStore(reducer);
渲染函数中的结构外部嵌套Provider并添加store
ReactDom.render(
<Provider store=store>
<APP/>
</Provider>,
document.getElementById('root')
);
有了Provider,我们也就不需要 store.dispatch()
了
它会帮我们处理渲染
最后的样式依然是那个样子
以上是关于React中的connect使用(Provider+Consumer例子 以及 contextType+this.context例子)的主要内容,如果未能解决你的问题,请参考以下文章
React-redux框架之connect()与Provider组件 用法讲解
React×Redux——react-redux库connect()方法与Provider组件