react-redux集中式状态管理及基本使用与优化
目录
- 1、react-redux
- 2、连接容器组件与UI组件
- 3、react-redux基本使用
- 优化1、简写mapState和mapDispatch两个映射方法
- 优化2、Provider组件的使用
- 优化3、整合UI组件与容器组件
- 优化总结
1、react-redux
react-redux把组件分为两类,一类叫做UI组件,一类叫做容器组件;
UI组件的外侧都要包裹一个容器组件。
注意️:本文使用的示例为之前的文章中的示例。在之前的文章中已经做过了介绍,在本文就不再阐述。
建议阅读顺序是:
【redux工作流程】
【redux异步action】
再到本文
2、连接容器组件与UI组件
UI组件存放在components文件夹中,我们可以在src目录下新建文件夹containers,专门用于存放容器组件
例如:Count组件的容器组件:/src/containers/Count/index.jsx
/* 该组件是Count组件这个UI组件的容器组件 */ // 引入Count组件的UI组件 import CountUI from '../../components/Count' // 引入connect用于连接UI组件与容器组件 import { connect } from 'react-redux' //创建并暴露一个Count的容器组件,connect()()的含义是:调用connect()这个函数返回的函数 export default connect()(CountUI)
代码解释:
引入CountUI,为Count组件的UI组件,从原理图中来看,该组件是Count容器组件的子组件。
引入connect函数,用于连接UI组件与容器组件;
我们从原理图中可以看出,redux要想工作,必须要连接UI组件与容器组件,还必须连接容器组件与store。
那么我们在容器组件中,使用connect()()的方法连接了UI组件
【connect()()的含义:调用connect()这个函数的返回值,返回值本身是一个函数,也就是调用返回的函数】
现在还需要让容器组件与store建立起连接;
怎么让容器组件与store建立起连接呢?
我们之前在App组件中一直都是渲染Count的UI组件的,但是我们现在引入了Count的容器组件(为Count的UI组件的父组件),那么我们可以直接在App组件中直接渲染Count组件的容器组件:
// App.jsx import React, { Component } from 'react' import Count from './containers/Count' import store from './redux/store' export default class App extends Component { render() { return ( <div> {/* 给容器组件传递store */} <Count store={store} /> </div> ) } }
重点️在于,
在渲染Count组件的容器组件时,通过组件的props属性,将store传入Count组件的容器组件,从而实现容器组件与store建立起连接。
3、react-redux基本使用
现在我们已经把UI组件与容器组件建立起连接了,并且将容器组件与store也建立起连接了,那么我们接下来一起来探索react-redux是怎么工作,如何使用的呢?
从流程图可以看出,我们需要向UI组件传递state(状态)和dispatch(操作状态的方法)。
但是我们在UI组件的父组件,也就是Count的容器组件中,并没有以组件标签()的形式去渲染子组件
而是通过react-redux提供的connect方法将父子组件建立起的联系,我们就需要通过connect方法传递props。
我们之前知道,我们在调用connect方法返回的函数时需要传递UI组件作为参数,以将容器组件与UI组件连接起来,也就是
connect()(CountUI)
而传递props时,我们需要在调用connect方法时直接传入两个参数(也就是connect的第一个括号内的参数),并且这两个参数都是函数形式的参数。具体看代码吧~
connect(mapStateToProps, mapDispatchToProps)(CountUI)
说明:第一个函数参数mapStateToProps作用是将存放在store中的状态映射给UI组件的props;
第二个函数参数mapDispatchToProps作用是将操作数据的方法映射给UI组件的props;
其实也就对应图中的
具体实现如下:
/* 该组件是Count组件这个UI组件的容器组件 */ import CountUI from '../../components/Count' import { connect } from 'react-redux' import { createIncrementAction, createDecrementAction, createIncrementAsyncAction } from '../../redux/count_action_creator' /* 1.mapStateToProps函数返回的是一个对象; 2.返回的对象中的key就作为传递给UI组件props的key,value就作为传递给UI组件props的value 3.mapStateToProps用于传递状态 */ function mapStateToProps(state) { return { count: state } } function mapDispatchToProps(dispatch) { return { jia: (data) => { // 通知redux执行加法 dispatch(createIncrementAction(data)) }, jian: (data) => { dispatch(createDecrementAction(data)) }, jiaAsync: (data, time) => { dispatch(createIncrementAsyncAction(data, time)) } } } //创建并暴露一个Count的容器组件,connect()()的含义是:调用connect()这个函数返回的函数 export default connect(mapStateToProps, mapDispatchToProps)(CountUI)
这样一来,Count的UI组件就会接收到传递进来的props,我们可以通过props去渲染状态和操作状态:
/src/components/Count/index.jsx:
渲染状态:
<h1>当前求和为:{this.props.count}</h1>
操作状态:
// 加法 increment = () => { const { value } = this.selectedNumber this.props.jia(value * 1) } // 减法 decrement = () => { const { value } = this.selectedNumber this.props.jian(value * 1) } // 和为奇数时,加 incrementIfOdd = () => { const { value } = this.selectedNumber if (this.props.count % 2 !== 0) { this.props.jia(value * 1) } } // 异步加 incrementAsync = () => { const { value } = this.selectedNumber this.props.jiaAsync(value * 1, 500) }
react-redux基本使用总结:
明确两个概念:UI组件与容器组件
UI组件:不能使用任何redux的api,只负责页面的呈现、交互等等;
容器组件:负责和redux通信,将结果交给UI组件
如何创建一个容器组件——靠react-redux 的 connect函数
connect(mapStateToProps, mapDispatchToProps)(CountUI)
mapStateToProps——映射状态,返回值是一个对象;
mapDispatchToProps——映射操作状态的方法,返回值是一个对象
备注:容器组件中的store是靠props传入的,而不是在容器组件中直接引入。
优化1、简写mapState和mapDispatch两个映射方法
原映射方法:
function mapStateToProps(state) { return { count: state } } function mapDispatchToProps(dispatch) { return { jia: (data) => { // 通知redux执行加法 dispatch(createIncrementAction(data)) }, jian: (data) => { dispatch(createDecrementAction(data)) }, jiaAsync: (data, time) => { dispatch(createIncrementAsyncAction(data, time)) } } }
简写成箭头函数:
const mapStateToProps = state => ({ count: state }) const mapDispatchToProps = dispatch => ( { jia: (data) => { // 通知redux执行加法 dispatch(createIncrementAction(data)) }, jian: (data) => { dispatch(createDecrementAction(data)) }, jiaAsync: (data, time) => { dispatch(createIncrementAsyncAction(data, time)) } } )
当然,这只是在编码的角度对函数进行简化,我们还可以在API的角度,实现mapDispatch更为简洁的写法。
其实mapDispatchToProps还可以是一个对象,在一般写法中,mapDispatchToProps是一个函数,但是可以简写成一个对象。
export default connect( state => ({ count: state }), // mapDispatchToProps的简写——是一个对象 { jia: createIncrementAction, jian: createDecrementAction, jiaAsync: createIncrementAsyncAction } // mapDispatchToProps一般写法——是一个函数 /* dispatch => ( { jia: (data) => { // 通知redux执行加法 dispatch(createIncrementAction(data)) }, jian: (data) => { dispatch(createDecrementAction(data)) }, jiaAsync: (data, time) => { dispatch(createIncrementAsyncAction(data, time)) } } ) */ )(CountUI)
把mapDispatchToProps简写成一个对象的话,react-redux会自动分发,也就是底层自动调用dispatch方法,所以我们在书写代码时并不需要手动调用dispatch方法,在mapDispatchToProps简写成一个对象时可以省略dispatch,这就是属于API层面的优化。
优化2、Provider组件的使用
在前面的连接容器组件和store的讲解中,我们提出:要想连接容器组件和store,就需要在App.jsx中通过props将store传入容器组件中。也就是这样子的:
// App.jsx import React, { Component } from 'react' import Count from './containers/Count' import store from './redux/store' export default class App extends Component { render() { return ( <div> {/* 给容器组件传递store */} <Count store={store} /> </div> ) } }
现在我们基于react-redux,可以对App组件进行优化:
// App.jsx import React, { Component } from 'react' import { Provider } from 'react-redux' import Count from './containers/Count' import store from './redux/store' export default class App extends Component { render() { return ( <div> {/* 给容器组件传递store */} <Provider store={store}> <Count /> </Provider> </div> ) } }
这样一来,哪怕我们需要连接多个容器组件到store,都只需要在渲染组件标签的外围包裹一个< Provider>标签即可。
优化3、整合UI组件与容器组件
前面两个优化,我们分别从代码层面和API层面进行了优化。在这里,我们将在文件层面对UI组件和容器组件进行优化。
我们前面在逐步学习实践react-redux时,将容器组件放在containers文件夹中。但是我们发现,如果需要使用redux的UI组件越来越多的话,需要的容器组件也越来越多,到最后可能项目中有20个组件需要使用redux中的状态,那么我们真的就另外创建20个容器组件吗?
Of course not ! Of course not! Ofcoursenot!
其实我们可以将UI组件与容器组件整合在同一个文件内!
/src/containers/Count/index.jsx:
import React, { Component } from 'react' // 引入connect用于连接UI组件与容器组件 import { connect } from 'react-redux' import { createIncrementAction, createDecrementAction, createIncrementAsyncAction } from '../../redux/count_action_creator' // 定义UI组件Count class Count extends Component { // 加法 increment = () => { const { value } = this.selectedNumber this.props.jia(value * 1) } // 减法 decrement = () => { const { value } = this.selectedNumber this.props.jian(value * 1) } // 和为奇数时,加 incrementIfOdd = () => { const { value } = this.selectedNumber if (this.props.count % 2 !== 0) { this.props.jia(value * 1) } } // 异步加 incrementAsync = () => { const { value } = this.selectedNumber this.props.jiaAsync(value * 1, 500) } render() { return ( <div> <h1>当前求和为:{this.props.count}</h1> <select ref={currentNode => { this.selectedNumber = currentNode }}> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> </select> <button onClick={this.increment}>加</button> <button onClick={this.decrement}>减</button> <button onClick={this.incrementIfOdd}>和为奇数时,加</button> <button onClick={this.incrementAsync}>异步加</button> </div> ) } } // 创建并暴露一个Count的容器组件,connect()()的含义是:调用connect()这个函数返回的函数 export default connect( state => ({ count: state }), // mapDispatchToProps的简写——是一个对象 { jia: createIncrementAction, jian: createDecrementAction, jiaAsync: createIncrementAsyncAction } // mapDispatchToProps一般写法——是一个函数 )(Count)
如此一来,我们就可以删除/src/components/Count/index.jsx了~
优化总结
容器组件和UI组件整合为同一个文件
无需自己给容器组件传递store,给包裹一个标签,在Provider内传递store即可;
使用了react-redux后也不用再自己监测redux中状态的改变了,容器组件可以自动完成这个工作;
mapDispatchToProps也可以简单的写成一个对象;
一个组件要和redux“打交道”要经过哪几步?
定义好UI组件——不暴露;引入connect生成一个容器组件,并暴露,写法如下:
connect( state => ({key:value}), //映射状态 {key:xxxxAction} //映射操作状态的方法 )(UI组件)
- 在UI组件中通过this.props读取和操作状态。
到此这篇关于集中式状态管理<react-redux>基本使用与优化的文章就介绍到这了,更多相关react-redux集中式状态管理内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!