react-redux集中式狀態(tài)管理及基本使用與優(yōu)化
1、react-redux

react-redux把組件分為兩類,一類叫做UI組件,一類叫做容器組件;
UI組件的外側(cè)都要包裹一個容器組件。
注意??:本文使用的示例為之前的文章中的示例。在之前的文章中已經(jīng)做過了介紹,在本文就不再闡述。
建議閱讀順序是:
【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'
//創(chuàng)建并暴露一個Count的容器組件,connect()()的含義是:調(diào)用connect()這個函數(shù)返回的函數(shù)
export default connect()(CountUI)
代碼解釋:
引入CountUI,為Count組件的UI組件,從原理圖中來看,該組件是Count容器組件的子組件。
引入connect函數(shù),用于連接UI組件與容器組件;
我們從原理圖中可以看出,redux要想工作,必須要連接UI組件與容器組件,還必須連接容器組件與store。
那么我們在容器組件中,使用connect()()的方法連接了UI組件
【connect()()的含義:調(diào)用connect()這個函數(shù)的返回值,返回值本身是一個函數(shù),也就是調(diào)用返回的函數(shù)】
現(xiàn)在還需要讓容器組件與store建立起連接;
怎么讓容器組件與store建立起連接呢?
我們之前在App組件中一直都是渲染Count的UI組件的,但是我們現(xiàn)在引入了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組件的容器組件,從而實現(xiàn)容器組件與store建立起連接。
3、react-redux基本使用
現(xiàn)在我們已經(jīng)把UI組件與容器組件建立起連接了,并且將容器組件與store也建立起連接了,那么我們接下來一起來探索react-redux是怎么工作,如何使用的呢?
從流程圖可以看出,我們需要向UI組件傳遞state(狀態(tài))和dispatch(操作狀態(tài)的方法)。
但是我們在UI組件的父組件,也就是Count的容器組件中,并沒有以組件標(biāo)簽()的形式去渲染子組件
而是通過react-redux提供的connect方法將父子組件建立起的聯(lián)系,我們就需要通過connect方法傳遞props。
我們之前知道,我們在調(diào)用connect方法返回的函數(shù)時需要傳遞UI組件作為參數(shù),以將容器組件與UI組件連接起來,也就是
connect()(CountUI)
而傳遞props時,我們需要在調(diào)用connect方法時直接傳入兩個參數(shù)(也就是connect的第一個括號內(nèi)的參數(shù)),并且這兩個參數(shù)都是函數(shù)形式的參數(shù)。具體看代碼吧~
connect(mapStateToProps, mapDispatchToProps)(CountUI)
說明:第一個函數(shù)參數(shù)mapStateToProps作用是將存放在store中的狀態(tài)映射給UI組件的props;
第二個函數(shù)參數(shù)mapDispatchToProps作用是將操作數(shù)據(jù)的方法映射給UI組件的props;
其實也就對應(yīng)圖中的

具體實現(xiàn)如下:
/*
該組件是Count組件這個UI組件的容器組件
*/
import CountUI from '../../components/Count'
import { connect } from 'react-redux'
import {
createIncrementAction,
createDecrementAction,
createIncrementAsyncAction
} from '../../redux/count_action_creator'
/*
1.mapStateToProps函數(shù)返回的是一個對象;
2.返回的對象中的key就作為傳遞給UI組件props的key,value就作為傳遞給UI組件props的value
3.mapStateToProps用于傳遞狀態(tài)
*/
function mapStateToProps(state) {
return { count: state }
}
function mapDispatchToProps(dispatch) {
return {
jia: (data) => {
// 通知redux執(zhí)行加法
dispatch(createIncrementAction(data))
},
jian: (data) => {
dispatch(createDecrementAction(data))
},
jiaAsync: (data, time) => {
dispatch(createIncrementAsyncAction(data, time))
}
}
}
//創(chuàng)建并暴露一個Count的容器組件,connect()()的含義是:調(diào)用connect()這個函數(shù)返回的函數(shù)
export default connect(mapStateToProps, mapDispatchToProps)(CountUI)
這樣一來,Count的UI組件就會接收到傳遞進(jìn)來的props,我們可以通過props去渲染狀態(tài)和操作狀態(tài):
/src/components/Count/index.jsx:
渲染狀態(tài):
<h1>當(dāng)前求和為:{this.props.count}</h1>
操作狀態(tài):
// 加法
increment = () => {
const { value } = this.selectedNumber
this.props.jia(value * 1)
}
// 減法
decrement = () => {
const { value } = this.selectedNumber
this.props.jian(value * 1)
}
// 和為奇數(shù)時,加
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基本使用總結(jié):
明確兩個概念:UI組件與容器組件
UI組件:不能使用任何redux的api,只負(fù)責(zé)頁面的呈現(xiàn)、交互等等;
容器組件:負(fù)責(zé)和redux通信,將結(jié)果交給UI組件
如何創(chuàng)建一個容器組件——靠react-redux 的 connect函數(shù)
connect(mapStateToProps, mapDispatchToProps)(CountUI)
mapStateToProps——映射狀態(tài),返回值是一個對象;
mapDispatchToProps——映射操作狀態(tài)的方法,返回值是一個對象
備注:容器組件中的store是靠props傳入的,而不是在容器組件中直接引入。
優(yōu)化1、簡寫mapState和mapDispatch兩個映射方法
原映射方法:
function mapStateToProps(state) {
return { count: state }
}
function mapDispatchToProps(dispatch) {
return {
jia: (data) => {
// 通知redux執(zhí)行加法
dispatch(createIncrementAction(data))
},
jian: (data) => {
dispatch(createDecrementAction(data))
},
jiaAsync: (data, time) => {
dispatch(createIncrementAsyncAction(data, time))
}
}
}
簡寫成箭頭函數(shù):
const mapStateToProps = state => ({ count: state })
const mapDispatchToProps = dispatch => (
{
jia: (data) => {
// 通知redux執(zhí)行加法
dispatch(createIncrementAction(data))
},
jian: (data) => {
dispatch(createDecrementAction(data))
},
jiaAsync: (data, time) => {
dispatch(createIncrementAsyncAction(data, time))
}
}
)
當(dāng)然,這只是在編碼的角度對函數(shù)進(jìn)行簡化,我們還可以在API的角度,實現(xiàn)mapDispatch更為簡潔的寫法。
其實mapDispatchToProps還可以是一個對象,在一般寫法中,mapDispatchToProps是一個函數(shù),但是可以簡寫成一個對象。
export default connect(
state => ({ count: state }),
// mapDispatchToProps的簡寫——是一個對象
{
jia: createIncrementAction,
jian: createDecrementAction,
jiaAsync: createIncrementAsyncAction
}
// mapDispatchToProps一般寫法——是一個函數(shù)
/* dispatch => (
{
jia: (data) => {
// 通知redux執(zhí)行加法
dispatch(createIncrementAction(data))
},
jian: (data) => {
dispatch(createDecrementAction(data))
},
jiaAsync: (data, time) => {
dispatch(createIncrementAsyncAction(data, time))
}
}
) */
)(CountUI)
把mapDispatchToProps簡寫成一個對象的話,react-redux會自動分發(fā),也就是底層自動調(diào)用dispatch方法,所以我們在書寫代碼時并不需要手動調(diào)用dispatch方法,在mapDispatchToProps簡寫成一個對象時可以省略dispatch,這就是屬于API層面的優(yōu)化。
優(yōu)化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>
)
}
}
現(xiàn)在我們基于react-redux,可以對App組件進(jìn)行優(yōu)化:
// 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,都只需要在渲染組件標(biāo)簽的外圍包裹一個< Provider>標(biāo)簽即可。
優(yōu)化3、整合UI組件與容器組件
前面兩個優(yōu)化,我們分別從代碼層面和API層面進(jìn)行了優(yōu)化。在這里,我們將在文件層面對UI組件和容器組件進(jìn)行優(yōu)化。
我們前面在逐步學(xué)習(xí)實踐react-redux時,將容器組件放在containers文件夾中。但是我們發(fā)現(xiàn),如果需要使用redux的UI組件越來越多的話,需要的容器組件也越來越多,到最后可能項目中有20個組件需要使用redux中的狀態(tài),那么我們真的就另外創(chuàng)建20個容器組件嗎?
Of course not ! Of course not! Ofcoursenot!
其實我們可以將UI組件與容器組件整合在同一個文件內(nèi)!
/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)
}
// 和為奇數(shù)時,加
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>當(dāng)前求和為:{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}>和為奇數(shù)時,加</button>
<button onClick={this.incrementAsync}>異步加</button>
</div>
)
}
}
// 創(chuàng)建并暴露一個Count的容器組件,connect()()的含義是:調(diào)用connect()這個函數(shù)返回的函數(shù)
export default connect(
state => ({ count: state }),
// mapDispatchToProps的簡寫——是一個對象
{
jia: createIncrementAction,
jian: createDecrementAction,
jiaAsync: createIncrementAsyncAction
}
// mapDispatchToProps一般寫法——是一個函數(shù)
)(Count)
如此一來,我們就可以刪除/src/components/Count/index.jsx了~
優(yōu)化總結(jié)
容器組件和UI組件整合為同一個文件
無需自己給容器組件傳遞store,給包裹一個標(biāo)簽,在Provider內(nèi)傳遞store即可;
使用了react-redux后也不用再自己監(jiān)測redux中狀態(tài)的改變了,容器組件可以自動完成這個工作;
mapDispatchToProps也可以簡單的寫成一個對象;
一個組件要和redux“打交道”要經(jīng)過哪幾步?
定義好UI組件——不暴露;引入connect生成一個容器組件,并暴露,寫法如下:
connect(
state => ({key:value}), //映射狀態(tài)
{key:xxxxAction} //映射操作狀態(tài)的方法
)(UI組件)
- 在UI組件中通過this.props讀取和操作狀態(tài)。
到此這篇關(guān)于集中式狀態(tài)管理<react-redux>基本使用與優(yōu)化的文章就介紹到這了,更多相關(guān)react-redux集中式狀態(tài)管理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用react context 實現(xiàn)vue插槽slot功能
這篇文章主要介紹了使用react context 實現(xiàn)vue插槽slot功能,文中給大家介紹了vue的slot的實現(xiàn)方法,需要的朋友可以參考下2019-07-07
使用webpack5從0到1搭建一個react項目的實現(xiàn)步驟
這篇文章主要介紹了使用webpack5從0到1搭建一個react項目的實現(xiàn)步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
React 遞歸手寫流程圖展示樹形數(shù)據(jù)的操作方法
這篇文章主要介紹了React 遞歸手寫流程圖展示樹形數(shù)據(jù)的操作方法,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2023-11-11
React?Fiber構(gòu)建completeWork源碼解析
這篇文章主要為大家介紹了React?Fiber構(gòu)建completeWork源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02
react koa rematch 如何打造一套服務(wù)端渲染架子
這篇文章主要介紹了react koa rematch 如何打造一套服務(wù)端渲染架子,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06

