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> ) } }
重點(diǎn)??在于,
在渲染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-12React 遞歸手寫流程圖展示樹形數(shù)據(jù)的操作方法
這篇文章主要介紹了React 遞歸手寫流程圖展示樹形數(shù)據(jù)的操作方法,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2023-11-11React?Fiber構(gòu)建completeWork源碼解析
這篇文章主要為大家介紹了React?Fiber構(gòu)建completeWork源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02react koa rematch 如何打造一套服務(wù)端渲染架子
這篇文章主要介紹了react koa rematch 如何打造一套服務(wù)端渲染架子,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06