什么是React-Redux
React-Redux 是Redux 官方出品的,用于配合React的綁定庫(kù)。
說(shuō)到Redux,簡(jiǎn)單來(lái)說(shuō)它就是一個(gè)狀態(tài)管理庫(kù)。在多層組件傳遞props十分繁瑣嗦明,也會(huì)使得組件的數(shù)據(jù)變得非常混亂舍败,但通過(guò)使用Redux招狸,這些問(wèn)題就能得到解決。
想要學(xué)會(huì)使用React-Redux 主要有以下幾個(gè)知識(shí)點(diǎn)需要掌握:
- 安裝以及起手式
- 搭建頁(yè)面結(jié)構(gòu)
- 導(dǎo)入provider組件
- 組件A發(fā)送 action
- 組件B接收 action
目標(biāo)效果
我們需要通過(guò)React-Redux完成一個(gè)頁(yè)面邻薯,它有以下內(nèi)容:
0 <--初始值
【+1按鈕】 <--當(dāng)我們點(diǎn)擊 +1 按鈕 的時(shí)候裙戏,上面的初始值+1
安裝以及起手式
安裝:
創(chuàng)建一個(gè)新的React應(yīng)用的并附帶Redux的時(shí)候:
npx create-react-app react-redux-example
在創(chuàng)建好的React中添加Redux:
npm install redux react-redux
接下來(lái)是起手式:
在src目錄下構(gòu)建 store 和 reducer
構(gòu)建reducer
reducer是一個(gè)純函數(shù),它接收之前的state和action作為參數(shù)厕诡,返回一個(gè)更新了的state累榜。
.src/reducer/index.js
,構(gòu)建該文件作為 reducer 來(lái)響應(yīng) actions
//接收兩個(gè)參數(shù)
//第一個(gè)參數(shù)是state
//第二個(gè)參數(shù)是action
//初始數(shù)據(jù)
const initialState = {
count: 0
}
//reducer要接受action然后進(jìn)行邏輯處理的
//判斷發(fā)送過(guò)來(lái)的action是不是我們而要的
//如果是我們需要的,就應(yīng)該 return一個(gè)新的state了(以對(duì)象的形式)
const reducer = (state = initialState, action) => {
switch (action.type) {
case "add_action":
return { count: state.count + 1}
default:
return state
}
}
export default reducer
構(gòu)建store
store是react項(xiàng)目中存儲(chǔ)state的地方灵嫌,你可以把它看成是一個(gè)大的JavaScript對(duì)象壹罚。創(chuàng)建store時(shí)我們需要一個(gè)reducer來(lái)作為參數(shù),我們已經(jīng)創(chuàng)建好reducer了寿羞,讓我們把它關(guān)聯(lián)到store上面吧猖凛。
.src/store/index.js
,通過(guò) createStore 方法 绪穆,把 reducer 傳入
//導(dǎo)入createStore方法
import {createStore} form 'redux'
//導(dǎo)入上面編寫(xiě)好的reducer
import {reducer} form '../reducer'
//構(gòu)建store
export default createStore(reducer)
接下來(lái)需要在 app.js
中引入store
(這里我提前把App.js
的結(jié)構(gòu)寫(xiě)好了辨泳,App
組件包裹著CompA
和CompB
兩個(gè)組件)
.scr/App.js
文件
import React from "react"
import "./App.css"
// 導(dǎo)入上面構(gòu)建好的store
import store from "./store"
//引入組件A
import CompA from './pages/compA.js'
//引入組件B
import CompA from './pages/compB.js'
function App() {
return (
<div className = "App">
<CompA/>
<CompB/>
</div>
)
}
export default App
搭建頁(yè)面結(jié)構(gòu)
這里為了演示如何使用Redux
虱岂,我選取了一個(gè)盡量簡(jiǎn)單的頁(yè)面結(jié)構(gòu)案例。
創(chuàng)建頁(yè)面組件A(用來(lái)發(fā)送action)
./src/pages/CompA.js
//里面暫時(shí)先不寫(xiě)東西
創(chuàng)建頁(yè)面組件B(用來(lái)接收A發(fā)出的action)
./src/pages/CompB.js
//里面暫時(shí)也不寫(xiě)東西
好的菠红,到目前為止第岖,我們有了:
- 一個(gè)
reducer
,它接收 action 并且進(jìn)行相應(yīng)的處理试溯。 - 一個(gè)
store
蔑滓,它通過(guò) redux 的 createStore 方法使用我們上面的reducer來(lái)構(gòu)建一個(gè)store。 - 一個(gè)
App.js
文件遇绞,它導(dǎo)入了上面創(chuàng)建好的 store键袱。并且在它的<App/>
組件里面,包裹了2個(gè)子組件摹闽,分別是用來(lái)發(fā)送 action 的 A組件 和用來(lái)接收 action 的 B組件杠纵。
導(dǎo)入provider(把store關(guān)聯(lián)到React)
想把store關(guān)聯(lián)到React,我們需要引入一個(gè)輔助函數(shù)叫做Provider钩骇。然后用Provider組件包裹著App組件,再把store作為props值傳入Provider铝量。
在App.js
文件中導(dǎo)入provider
倘屹,并用它包裹整個(gè)應(yīng)用
還是這個(gè).scr/App.js
文件
import React from "react"
import "./App.css"
// 導(dǎo)入上面構(gòu)建好的store
import store from "./store"
//這里
//這里
//這里
//多了一步導(dǎo)入Provider組件,并且利用它包裹整個(gè)結(jié)構(gòu) 慢叨,從而達(dá)到統(tǒng)一維護(hù)的目的纽匙。
import {Provider} from "react-redux"
//引入組件A
import CompA from './pages/compA.js'
//引入組件B
import CompA from './pages/compB.js'
function App() {
return (
<Provider store = {store}>
<div className = "App">
<CompA/>
<CompB/>
</div>
</Provider>
)
}
export default App
組件A發(fā)送 action
action包含著各種類(lèi)型,比如REMOVE_ARTICLE 或者 ADD_ARTICLE等拍谐。它從react組件中被分發(fā)(傳遞數(shù)據(jù))到redux 的 store 中烛缔。當(dāng)讓action只是一個(gè)傳遞信息的,他不能改變store轩拨。store只能被reducer改變践瓷。
上面的 ./src/pages/CompA.js
編寫(xiě)好之后是這樣子的
class CompA extends React.Component {
handleClick = () =>{
//
this.props.sendAction()
}
render() {
return <button onClick={this.handleClick}> + </button>
}
}
const mapDispatchToProps = dispatch => {
return {
sendAction: () => {
//利用 dispatch 發(fā)送一個(gè) action
//傳遞 action 對(duì)象時(shí)需要定義一個(gè) type 屬性
//返回一個(gè)對(duì)象
dispatch({
type: "add_action"
})
}
}
}
// A 是發(fā)送方,所以要實(shí)現(xiàn) connect 第二個(gè)參數(shù)
export default connect(null,mapDispatchToProps)(CompA)
在組件A 里面亡蓉,我們做了這些事情:
- 導(dǎo)入
connect
- 利用
connect
對(duì)組件進(jìn)行加強(qiáng) - 由于A是發(fā)送方晕翠,所以需要實(shí)現(xiàn)
connect
第二個(gè)參數(shù) - 構(gòu)建了一個(gè)函數(shù)
mapDispatchToProps(dispatch)
dispatch
就是用來(lái)發(fā)送action
的 - 在上面這個(gè)函數(shù)中就可以返回一個(gè)對(duì)象
key
是方法名(sendAction)
value
(箭頭函數(shù)):調(diào)用dispatch
去發(fā)送action
- 在組件中的 內(nèi)容就可以通過(guò)
this.props
來(lái)拿到這個(gè)方法了。
數(shù)據(jù)走到了上面的reducer中
通過(guò)之前的createStore(reducer)
/*
接收2個(gè)參數(shù)
第一個(gè)是 state
第二個(gè)是 action
*/
const initState = {
count: 0
}
// reducer 要接收 action 然后進(jìn)行邏輯處理
// 它判斷 action 的type 如果是我們需要的砍濒,則執(zhí)行對(duì)應(yīng)的行為 (return 一個(gè)新的state)
const reducer = (state = initState,action) => {
switch (action.type) {
case "add_action":
return {
count: state.count + 1
}
default :
return state
}
}
export default reducer
組件B 接收 state
import React from "react";
//導(dǎo)入 connect
import { connect } from "react-redux"
class CompB extends React.Component {
render() {
return <div>{this.props.count}</div>
}
}
//接收兩個(gè)參數(shù)
const mapStateToProps = state => {
return state
}
//組件B 是接收方淋肾,所以需要實(shí)現(xiàn) connect 方法的第一個(gè)參數(shù)
export default connect(mapStateToProps)(CompB)
在B組件中,我們做了這些事情:
- 導(dǎo)入
connect
方法 - 利用
connect
對(duì)組件進(jìn)行加強(qiáng) - 組件B是接收方爸邢,所以需要實(shí)現(xiàn)
connect
方法的第一個(gè)參數(shù) -
mapStateToProps
里面的第一個(gè)參數(shù)就是我們很關(guān)心的state
- 把這個(gè)
state
進(jìn)行return
才能在組件內(nèi)部獲取到最新的數(shù)據(jù) - 組件B 是否能拿到數(shù)據(jù)的關(guān)鍵是
reducer
- 只有
reducer
里面返回了新的state
的時(shí)候樊卓,我們才能獲取到數(shù)據(jù)。
最終顯示效果
0 <--初始值
【+1按鈕】 <--當(dāng)我們點(diǎn)擊 +1 按鈕 的時(shí)候杠河,上面的初始值+1