react-redux高阶组件connect方法使用介绍以及实现原理
2018-01-26 20:38
1596 查看
redux
讲
connect之前先来回顾一下
redux的基本用法, 见下面的例子:
import { createStore } from 'redux'; function counter(state = 0, action) { switch (action.type) { case 'INCREMENT': return state + 1; case 'DECREMENT': return state - 1; default: return state; } } // 创建 Redux store 来存放应用的状态。 // API 是 { subscribe, dispatch, getState }。 let store = createStore(counter); // 可以手动订阅更新,也可以事件绑定到视图层。 store.subscribe(() => console.log(store.getState()) ); // 改变内部 state 惟一方法是 dispatch 一个 action。 store.dispatch({ type: 'INCREMENT' }); // 1 store.dispatch({ type: 'INCREMENT' }); // 2 store.dispatch({ type: 'DECREMENT' }); // 1
以上总结起来就只有下面四个方法
let store = createStore(reducer); // 创建store store.getState( ); // 获取state值 store.dispatch({ type: "text" }); // 使用action更改在reducer中定义好的更改store的更改策略 store.subScribe(render); // 设置监听函数, 在更改store之后触发
关于
redux的更多内容, 可以参阅官方文档.
好了, 进入正题
react-redux 高阶组件 connect方法介绍以及实现原理
在使用介绍connect之前, 先简单介绍一下什么是高阶组件.
高阶组件
高阶组件就是一个函数,传给它一个组件,它返回一个新的组件。 实际上就是一个类工厂, 见下面的一个例子.import React, { Component } from 'react' export default (People) => { class Star extends Component { // 可以做很多自定义逻辑 render () { return <People/> } } return Star }
这就好比一个普通的人, 经过公司的包装之后, 变成一个会很多种技能的明星一样.
import React, { Component } from 'react' export default (People, things) => { class Star extends Component { constructor () { super() this.state = { data: null } } componentWillMount () { ajax.get('/data/' + things, (data) => { this.setState({ data }) }) } render () { return <People data={this.state.data} /> } } return Star }
在
People推上市场之前, 先告诉公司他需要什么
things, 然后公司在
componentWillMount阶段对他需要的
things进行准备, 最后返回一个
Star
React.js 的 context
还要再说一个小概念, 如果不提这个无法讲述connect的实现原理, 因此如果不想看原理只想看使用方法的话, 这一部分可以跳过, 不过博主会用简单的语言描述这个问题, 最好看一下.ヾ(◍°∇°◍)ノ゙某个组件只要往自己的
context里面放了某些状态,这个组件之下的所有子组件都直接访问这个状态而不需要通过中间组件的传递。一个组件的
context只有它的子组件能够访问,它的父组件是不能访问到的,你可以理解每个组件的
context就是瀑布的源头,只能往下流不能往上飞。
那么怎么设置
context呢? 见下面的代码
class Parent extends Component { // 父组件 static childContextTypes = { tags: PropTypes.string } constructor () { super() this.state = { tags: 'hello' } } getChildContext () { return { index: this.state.tags } } render () { return ( <div> <Title /> </div> ) } } class Title extends Component { static contextTypes = { tags: PropTypes.string } render () { return ( <h1>{ this.context.tags }</h1> ) } }
总的来说:
一个组件可以通过
getChildContext方法返回一个对象, 这个对象就是子树的
context, 提供
context的组件必须提供
childContextTypes作为
context的声明和验证.
如果一个组件设置了
context, 那么它的子组件都可以直接访问到里面的内容, 它就像这个组件为根的子树的全局变量。任意深度的子组件都可以通过
contextTypes来声明你想要的
context里面的哪些状态, 然后可以通过
this.context访问到那些状态.
connect
connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])
connect有四个参数, 但是后两个参数用到的很少, 所以本篇博客之探讨前两个参数.
connect 的第一个参数是 mapStateToProps
这个函数允许我们将 store 中的数据作为 props 绑定到组件上
const mapStateToProps = (state) => { // 正常我们在react-redux中会这样书写 return { themeColor: state.themeColor } } People = connect(mapStateToProps)(People) // connect返回来的是一个函数, 因此还要再一次调用传入组件
实现主要原理, 就是将需要绑定的
props作为一个函数传过来, 在
connect中传给
mapStateToProps一个真实的
store的数据
const connect = (mapStateToProps) => (People) => { class Connect extends Component { static contextTypes = { store: PropTypes.object } constructor () { super() this.state = { allProps: {} } } componentWillMount () { const { store } = this.context this.setProps() } setProps () { const { store } = this.context let stateProps = mapStateToProps(store.getState(), this.props) // 额外传入 props this.setState({ allProps: { // 整合普通的 props 和从 state 生成的 props ...stateProps, ...this.props } }) } render () { return <People {...this.state.allProps} /> } } return Connect }
connect 的第二个参数是 mapDispatchToProps
由于更改数据必须要触发action, 因此在这里的主要功能是将
action作为
props绑定到 组件上
const mapDispatchToProps = (dispatch, ownProps) => { return { increase: (...args) => dispatch(actions.increase(...args)), decrease: (...args) => dispatch(actions.decrease(...args)) } } class People extends Component { render(){ const {count, increase, decrease} = this.props; return (<div> <div>计数:{this.props.count}次</div> <button onClick={increase}>增加</button> <button onClick={decrease}>减少</button> </div>) } } const NiuPeople = connect(mapStateToProps, mapDispatchToProps)(People);
这里的实现原理和上面的相差不多, 主要是将
action和
props一起传到组件里.
const connect = (mapStateToProps, mapDispatchToProps) => (People) => { class Connect extends Component { static contextTypes = { store: PropTypes.object } constructor () { super() this.state = { allProps: {} } } componentWillMount () { const { store } = this.context this.setProps() store.subscribe(() => this.setProps()) } setProps () { // 做了一下完整性的判断 const { store } = this.context let stateProps = mapStateToProps ? mapStateToProps(store.getState(), this.props) : {} // 防止 mapStateToProps 没有传入 let dispatchProps = mapDispatchToProps ? mapDispatchToProps(store.dispatch, this.props) : {} // 防止 mapDispatchToProps 没有传入 this.setState({ allProps: { ...stateProps, ...dispatchProps, ...this.props } }) } render () { return <People {...this.state.allProps} /> } } return Connect }
Provider
这是最后一个要说的问题, 讲到这里可能有一个疑问, 就是context是什么时候设置的呢. 下面要说的就是这个问题.Provider就是
react-redux中的一个组件,
Provider做的事情也简单, 它就是一个容器组件, 会把嵌套的内容原封不动作为自己的子组件渲染出来. 它还会把外界传给它的
props.store放到
context, 这样子组件
connect的时候都可以获取到. 见下面代码.
class Provider extends Component { static propTypes = { store: PropTypes.object, children: PropTypes.any } static childContextTypes = { store: PropTypes.object } getChildContext () { return { store: this.props.store } } render () { return ( <div>{this.props.children}</div> ) } }
参考地址:
作者: 胡子大哈 http://huziketang.com/books/react/lesson40
作者: 沈斯明 http://blog.csdn.net/u010977147/article/details/53412381
相关文章推荐
- mdev的使用方法和原理以及实现U盘或SD卡的自动挂载
- C语言中strtok使用方法与原理,以及自实现函数功能
- 4000 Oracle游标的使用方法以及使用for循环实现游标的原理
- 【干货】利用MVC5+EF6搭建博客系统(四)(上)前后台页面布局页面实现,介绍使用的UI框架以及JS组件
- android学习笔记---57_采用方向传感器实现指南针,android设备传感器介绍,以及使用方法
- mdev的使用方法和原理以及实现U盘或SD卡的自动挂载
- 使用React的static方法实现同构以及同构的常见问题
- React×Redux——react-redux库connect()方法与Provider组件
- 详解关于react-redux中的connect用法介绍及原理解析
- SAMBA 的实现原理以及使用方法
- 线程池的原理以及实现线程池的类ExecutorService中方法的使用
- Lucene.net 原理介绍以及使用方法
- 线程池的原理以及实现线程池的类ExecutorService中方法的使用
- 使用React的static方法实现同构以及同构的常见问题
- Lucene.net 原理介绍以及使用方法
- mdev的使用方法和原理以及实现U盘或SD卡的自动挂载
- mdev的使用方法和原理以及实现U盘或SD卡的自动挂载
- Android 四大组件之(2)Service实现原理以及AIDL语言的使用详解
- Laravel 5.3 使用内置的 Auth 组件实现多用户认证功能以及登陆才能访问后台的功能的一种实现方法
- mdev的使用方法和原理以及实现U盘或SD卡的自动挂载