上篇文章初步了解和学习了react-redux的原理和组件拆分
今天探索一下react-redux基本使用以及对求和案例的代码优化
感兴趣的小伙伴一起来看看吧!
根据react-redux模型图,实现了Count的容器组件与Count的UI组件的联系,接下来要实现容器组件给UI组件传递 redux中所保存的状态以及操作状态的方法,要借助props
。
但是不能像原先父子组件传参利用标签的方式传递,比如:
<A>
<B a='1' b='2'/>
<A/>
那么如何在容器组件(父组件)向UI组件传递参数呢?
由于父子组件关系是靠connect形成的,所以connect函数在第一次调用的时候要传入两个参数,参数必须是函数类型的,这样react-redux库就帮你调用这两个函数,一个函数返回值作为状态,另一个函数返回值作为操作状态的方法。
// react-redux API默认要给connect两个函数作为参数,两个函数会收到来至redux传来的值和方法。
export default connect(mapStateToProps, mapDispatchToProps)(CountUI)
mapStateToProps()函数的返回值作为 状态
传递给了UI组件,函数返回的是一个对象,mapStateToProps函数返回的对象中的key就作为传递给UI组件props的key,value就作为传递给UI组件props的value。
由于要获取redux里的状态,就要store.getState(),就要在容器组件里引入store,但是之前已经在上层App.jsx里向容器组件传了store,就不需要自己引入了,这里也不需要我们自己去获取状态,react-redux帮我们调mapStateToProps()函数时,已经帮我们把状态传过去了,只需要mapStateToProps(state)接收一下即可。
function mapStateToProps(state) {
return { count: state }
}
这样UI组件就可以通过 this.props 接收到 状态:
<h1>当前求和为:{this.props.count}</h1>
mapDispatchToProps()函数的返回值作为 操作状态的方法
传递给了UI组件,函数返回的是一个对象,mapDispatchToProps函数返回的对象中的key就作为传递给UI组件props的key,value就作为传递给UI组件props的value。
由于要实现加这个运算,就要在jia这个回调函数里通知redux执行加法,就要调用store.dispatch(action)这个方法,这里又要引入store操作状态,但是这里也不需要store调用dispatch方法,react-redux帮我们把dispatch()方法传过去了,直接用即可。
// 引入action
import {
createIncrementAction,
createDecrementAction,
createIncrementAsyncAction
} from '../../redux/count_action'
function mapDispatchToProps(dispatch) {
return {
jia: (number) => {
// 通知redux执行加法
dispatch(createIncrementAction(number))
},
jian: (number) => {
// 通知redux执行减法
dispatch(createDecrementAction(number))
},
jiaAsync: (number, time) => {
// 通知redux执行异步加法
dispatch(createIncrementAsyncAction(number, time))
}
}
}
这样UI组件就可以通过 this.props 接收到 操作状态的方法:
// 加法
increment = () => {
// 获取用户输入
const { value } = this.selectNumber
this.props.jia(value * 1)
}
// 减法
decrement = () => {
// 获取用户输入
const { value } = this.selectNumber
this.props.jian(value * 1)
}
// 奇数再加
incrementIfOdd = () => {
// 获取用户输入
const { value } = this.selectNumber
if (this.props.count % 2 !== 0) {
this.props.jia(value * 1)
}
}
// 异步加
incrementAsync = () => {
// 获取用户输入
const { value } = this.selectNumber
this.props.jiaAsync(value * 1, 500)
}
src=> components=> Count => index.jsx:
import React, { Component } from 'react'
export default class Count extends Component {
// 加法
increment = () => {
// 获取用户输入
const { value } = this.selectNumber
this.props.jia(value * 1)
}
// 减法
decrement = () => {
// 获取用户输入
const { value } = this.selectNumber
this.props.jian(value * 1)
}
// 奇数再加
incrementIfOdd = () => {
// 获取用户输入
const { value } = this.selectNumber
if (this.props.count % 2 !== 0) {
this.props.jia(value * 1)
}
}
// 异步加
incrementAsync = () => {
// 获取用户输入
const { value } = this.selectNumber
this.props.jiaAsync(value * 1, 500)
}
render() {
// console.log('UI组件接收到的props是:', this.props)
return (
<div>
<h1>当前求和为:{this.props.count}</h1>
<select ref={c => this.selectNumber = c}>
<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>
)
}
}
src=> containers=> Count => index.jsx:
// 引入Count的UI组件
import CountUI from '../../components/Count'
// 引入action
import {
createIncrementAction,
createDecrementAction,
createIncrementAsyncAction
} from '../../redux/count_action'
// 引入connect用于连接UI组件与redux
import { connect } from 'react-redux'
function mapStateToProps(state) {
return { count: state }
}
function mapDispatchToProps(dispatch) {
return {
jia: (number) => {
// 通知redux执行加法
dispatch(createIncrementAction(number))
},
jian: (number) => {
dispatch(createDecrementAction(number))
},
jiaAsync: (number, time) => {
dispatch(createIncrementAsyncAction(number, time))
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(CountUI)
1️⃣明确两个概念:
- UI组件:不能使用任何redux的api,只负责页面的呈现、交互等。
- 容器组件:负责和redux通信,将结果交给UI组件。
2️⃣如何创建一个容器组件———依靠react-redux的connect函数
connect(mapStateToProps,mapDispatchToProps)(UI组件)
- mapStateToProps:映射状态,返回值是一个对象
- mapDispatchToProps:映射操作状态的方法,返回值是一个对象
3️⃣ 备注:容器组件中的store是靠props传进去的,而不是在容器组件中直接引入。
优化前:
// 映射状态
function mapStateToProps(state) {
return { count: state }
}
优化后:
// 映射状态
const mapStateToProps = state => ({ count: state })
优化前:
// 映射操作状态的方法
function mapDispatchToProps(dispatch) {
return {
jia: (number) => {
// 通知redux执行加法
dispatch(createIncrementAction(number))
},
jian: (number) => {
dispatch(createDecrementAction(number))
},
jiaAsync: (number, time) => {
dispatch(createIncrementAsyncAction(number, time))
}
}
}
优化后:
// 映射操作状态的方法
const mapDispatchToProps = dispatch => (
{
jia: number => dispatch(createIncrementAction(number)),
jian: number => dispatch(createDecrementAction(number)),
jiaAsync: (number, time) =>
dispatch(createIncrementAsyncAction(number, time))
}
)
再优化后:
// 引入Count的UI组件
import CountUI from '../../components/Count'
// 引入action
import {
createIncrementAction,
createDecrementAction,
createIncrementAsyncAction
} from '../../redux/count_action'
// 引入connect用于连接UI组件与redux
import { connect } from 'react-redux'
//使用connect()()创建并暴露一个Count的容器组件
// react-redux API默认要给connect两个函数作为参数,两个函数会收到来至redux传来的值和方法。
export default connect(
state => ({ count: state }),
dispatch => (
{
jia: number => dispatch(createIncrementAction(number)),
jian: number => dispatch(createDecrementAction(number)),
jiaAsync: (number, time) =>
dispatch(createIncrementAsyncAction(number, time))
}
)
)(CountUI)
mapDispatchToProps的简写:
export default connect(
state => ({ count: state }),
// mapDispatchToProps的一般写法
// dispatch => (
// {
// jia: number => dispatch(createIncrementAction(number)),
// jian: number => dispatch(createDecrementAction(number)),
// jiaAsync: (number, time) =>
// dispatch(createIncrementAsyncAction(number, time))
// }
// )
// mapDispatchToProps的简写
{
jia: createIncrementAction,
jian: createDecrementAction,
jiaAsync: createIncrementAsyncAction
}
)(CountUI)
分析mapDispatchToProps的简写
{
jia: createIncrementAction,
jian: createDecrementAction,
jiaAsync: createIncrementAsyncAction
}
Count的UI组件里调用了jia函数,传递了用户选择的参数,然后在容器组件里调用了createIncrementAction方法,返回值是一个action对象,react-redux帮我们自动dispatch
了。
mapDispatchToProps可以写成
一个普通的函数
,也可以是一个对象
。
react-redux还有一个优势:不用自己监测redux的状态是否发生了变化,内部的所有逻辑全部交给容器组件来完成,避免污染整个app组件。
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>
)
}
}
当项目中有多个容器组件时,每次都要给容器组件传递store,这样不太方便,所以:我们可以在index.js入口文件里引入react-redux里的一个API——Provider
。
把所有容器组件都需要的store交给Provider,Provider会自动分析整个项目里所有的容器组件,把store传给每一个需要store的容器组件。
index.js:
import React from 'react';
import ReactDOM from 'react-dom/client'
import App from './App'
import store from './redux/store'
import { Provider } from 'react-redux'
// 创建虚拟DOM
const root = ReactDOM.createRoot(document.getElementById('root'))
// 渲染虚拟DOM到页面
root.render(
<React.StrictMode>
{/* 检查App组件以及子组件里的一些代码是否有不合理的地方 */}
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
)
前面两个优化,我们分别从代码层面和API层面进行了优化。在这里,我们将在文件层面对UI组件和容器组件进行优化。
由于我们学习了react-redux库,要求为组件分别写成UI组件和容器组件。那么如果在整个应用中,有20个组件需要和redux打交道,那么我们就需要写40个组件…可想而知,这样写是不行的,我们可以作出一些优化:
可以将UI组件和容器组件整合在同一个文件夹里。
/src/containers/Count/index.jsx:
import React, { Component } from 'react'
// 引入action
import {
createIncrementAction,
createDecrementAction,
createIncrementAsyncAction
} from '../../redux/count_action'
// 引入connect用于连接UI组件与redux
import { connect } from 'react-redux'
// 定义UI组件
class Count extends Component {
// 加法
increment = () => {
const { value } = this.selectNumber
this.props.jia(value * 1)
}
// 减法
decrement = () => {
const { value } = this.selectNumber
this.props.jian(value * 1)
}
// 奇数再加
incrementIfOdd = () => {
const { value } = this.selectNumber
if (this.props.count % 2 !== 0) {
this.props.jia(value * 1)
}
}
// 异步加
incrementAsync = () => {
const { value } = this.selectNumber
this.props.jiaAsync(value * 1, 500)
}
render() {
return (
<div>
<h1>当前求和为:{this.props.count}</h1>
<select ref={c => this.selectNumber = c}>
<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>
)
}
}
//使用connect()()创建并暴露一个Count的容器组件
export default connect(
state => ({ count: state }),
// mapDispatchToProps的简写
{
jia: createIncrementAction,
jian: createDecrementAction,
jiaAsync: createIncrementAsyncAction
}
)(Count)
1️⃣ 容器组件和UI组件整合成一个文件
2️⃣ 无需自己给容器组件传递store,给 < < <App/>包裹一个 < < <Provider store={store}>即可。
3️⃣ 使用了react-redux后也不用再自己监测redux中状态的改变了,容器组件可以自动完成这个工作。
4️⃣ mapDispatchToProps也可以简单的写成一个对象。
5️⃣ 一个组件要和redux“打交道”要经过哪几步?
定义好UI组件—不暴露
引入connect生成一个容器组件,并暴露,写法如下:
connect( state => ({key:value}), //映射状态 {key:xxxxAction} //映射操作状态的方法 )(UI组件)
在UI组件中通过this.props.xxxxxx读取和操作状态
今天的分享就到这里啦✨ \textcolor{red}{今天的分享就到这里啦✨} 今天的分享就到这里啦✨
原创不易,还希望各位大佬支持一下 \textcolor{blue}{原创不易,还希望各位大佬支持一下} 原创不易,还希望各位大佬支持一下
点赞,你的认可是我创作的动力! \textcolor{green}{点赞,你的认可是我创作的动力!} 点赞,你的认可是我创作的动力!
⭐️ 收藏,你的青睐是我努力的方向! \textcolor{green}{收藏,你的青睐是我努力的方向!} 收藏,你的青睐是我努力的方向!
✏️ 评论,你的意见是我进步的财富! \textcolor{green}{评论,你的意见是我进步的财富!} 评论,你的意见是我进步的财富!