redux+react-redux+示例的快速上手體驗(yàn)
本文主要記錄下自己在react道路上的爬坑過(guò)程 以及對(duì)于剛學(xué)習(xí)redux的同學(xué)提供一些可供參考的例子芭毙。
之前用vue用了很久 vue的語(yǔ)法糖用起來(lái)是真的舒服 不過(guò)現(xiàn)在公司項(xiàng)目用的是react 只好默默的從vue轉(zhuǎn)到react 其實(shí)畢竟他們都是類(lèi)似的框架昆禽, 雖然語(yǔ)法大不同桩了, 但是有些地方的思想還是很像的疙咸, 廢話(huà)不多說(shuō)了睹逃,開(kāi)始正文...
本文主要分為兩個(gè)部分:redux和react-redux机隙。 首先大概過(guò)一下redux的基礎(chǔ)部分:
1.redux
要知道redux和react并沒(méi)有半毛錢(qián)的關(guān)系智玻,redux甚至可以和jq一起用桐绒。 react-redux才是react的用于便捷操作redux的第三方插件夺脾。所以呢之拨,學(xué)習(xí)react-redux之前我們要比較熟悉的了解redux的思想。本文比較直接咧叭,不來(lái)虛的蚀乔,直接上代碼:
首先就很熟悉了
1 使用官方腳手架
create-react-app redux-demo
2 環(huán)境搭建好之后 繼續(xù)安裝redux
npm install redux --S
進(jìn)入到項(xiàng)目文件夾 把我們用不到的全咔咔刪掉
在src/index.js里引入redux并創(chuàng)建action reducer和store
src/index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import { createStore } from 'redux'
//這是redux的原始state
const tiger = 10000
//這是action
const increase = {
type:'漲工資'
}
const decrease = {
type:'扣工資'
}
//這是reducer
const reducer = (state = tiger, action) => {
switch (action.type){
case '漲工資':
return state += 100;
case '扣工資':
return state -= 100;
default:
return state;
}
}
//創(chuàng)建store
const store = createStore(reducer);
console.log(store.getState())
ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();
這里大概解釋下每個(gè)的意思:
action:行為 它是一個(gè)對(duì)象 里面必有type來(lái)指定其類(lèi)型 這個(gè)類(lèi)型可以理解為你要做什么,reducer要根據(jù)action的type來(lái)返回不同的state 每個(gè)項(xiàng)目有且可以有多個(gè)action
reducer: 可以理解為一個(gè)專(zhuān)門(mén)處理state的工廠(chǎng) 給他一個(gè)舊數(shù)據(jù)它會(huì)根據(jù)不同action.type返回新的數(shù)據(jù) 也就是:舊state + action = 新state 每個(gè)項(xiàng)目有且可以有多個(gè)reducer
store: store本質(zhì)上是一個(gè)狀態(tài)樹(shù)菲茬,保存了所有對(duì)象的狀態(tài)吉挣。任何UI組件都能直接的從store訪(fǎng)問(wèn)特定對(duì)象的狀態(tài)。每個(gè)項(xiàng)目有且只能有一個(gè)store
腦子里有了這些基本的概念后我們就可以把reducer放到createStore里并創(chuàng)建好store了
可以看到 代碼的最后我們打印了store.getState() 這段代碼簡(jiǎn)單理解就是打印下store里的數(shù)據(jù)
因?yàn)槲覀冎皇菍?xiě)了action并沒(méi)有給它dispatch 所以reducer只會(huì)走默認(rèn)的default 所以?xún)H僅是返回state=tiger 那么tiger就是我們之前定義好的state
此時(shí)我們npm start 在瀏覽器打開(kāi)該demo f12打開(kāi)控制臺(tái) 可以看到打印的數(shù)據(jù)為:10000
這里我們只是簡(jiǎn)單的回顧下redux的基礎(chǔ)知識(shí) 并沒(méi)有在app.js里面寫(xiě)任何東西
好 可以看到在上面我們雖然定義了action 但是好像并沒(méi)有什么用巴竦睬魂? 接下來(lái)我們要做的事情就是讓它變化了。
剛才僅僅是獲得到初始的數(shù)據(jù) 這并不是我們想要的結(jié)果 在實(shí)際項(xiàng)目中我們肯定有很多的需求 不同需求對(duì)應(yīng)不同功能 不同功能獲得不同數(shù)據(jù)镀赌,所以接下來(lái)我們要用到dispatch給它派發(fā)不同的action氯哮,上代碼:
src/index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import { createStore } from 'redux'
const tiger = 10000
//這是action
const increase = {
type:'漲工資'
}
const decrease = {
type:'扣工資'
}
//這是reducer
const reducer = (state = tiger, action) => {
switch (action.type){
case '漲工資':
return state += 100;
case '扣工資':
return state -= 100;
default:
return state;
}
}
//創(chuàng)建store
const store = createStore(reducer);
//訂閱事件
store.subscribe(() =>
console.log(store.getState())
);
//派發(fā)事件
store.dispatch(increase)
ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();
可以看到, 打印的數(shù)據(jù)變成了 11000 也就是說(shuō)reducer根據(jù)dispatch派發(fā)的action的type商佛,return了新的state喉钢。當(dāng)然我們也可以派發(fā)store.dispatch(decrease) 那打印的結(jié)果就是 10000,原因想必大家都知道良姆。
其實(shí)我們僅僅是多寫(xiě)了store.dispatch(increase) 和 store.subscribe(() =>{}) 他們的每個(gè)作用大概解釋下:
dispatch的作用就是告訴reducer 我給你action, 你要根據(jù)我的action.type返回新的state出牧。 然后reducer就會(huì)根據(jù)action的type,返回新的state歇盼。
我們給它dispatch了action舔痕,reducer也做出相應(yīng) 最后也返回新的state 但是其實(shí)這時(shí)候console.log()不會(huì)打印新的數(shù)據(jù) 因?yàn)閟tate雖然變化了 但是還是打印store.getState()還是原始的數(shù)據(jù)
這時(shí)候我們就需要store.subscribe(() =>{})了 它的作用就是每當(dāng)reducer返回新的數(shù)據(jù) 它就會(huì)自動(dòng)更新頁(yè)面 把UI組件的state更新下 不然的話(huà) 雖然state變化了 頁(yè)面仍不會(huì)更新(雖然現(xiàn)在還沒(méi)有其他組件)
2.react-redux
好了, 這些就是基本的redux的知識(shí)豹缀。我們不難發(fā)現(xiàn)伯复,這樣其實(shí)挺麻煩的。你需要寫(xiě)好多好多東西邢笙,而且我們并沒(méi)有把reducer啸如,action什么的給分離出去,不然的話(huà)我還要往很多組件里面?zhèn)骱芏鄸|西氮惯。這對(duì)我們實(shí)際開(kāi)發(fā)是很不友好的叮雳。
所以, 這時(shí)候就十分迫切需要react-redux了妇汗。它的作用是幫助我們操作redux帘不。有了它我們可以很方便的寫(xiě)redux。接下來(lái)上代碼:
首先安裝react-redux:
`npm install react-redux --S`
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';
import { Provider, connect } from 'react-redux';
class App extends Component {
render() {
const { PayIncrease, PayDecrease } = this.props;
return (
<div className="App">
<div className="App">
<h2>當(dāng)月工資為{this.props.tiger}</h2>
<button onClick={PayIncrease}>升職加薪</button>
<button onClick={PayDecrease}>遲到罰款</button>
</div>
</div>
);
}
}
const tiger = 10000
//這是action
const increase = {
type: '漲工資'
}
const decrease = {
type: '扣工資'
}
//這是reducer
const reducer = (state = tiger, action) => {
switch (action.type) {
case '漲工資':
return state += 100;
case '扣工資':
return state -= 100;
default:
return state;
}
}
//創(chuàng)建store
const store = createStore(reducer);
//需要渲染什么數(shù)據(jù)
function mapStateToProps(state) {
return {
tiger: state
}
}
//需要觸發(fā)什么行為
function mapDispatchToProps(dispatch) {
return {
PayIncrease: () => dispatch({ type: '漲工資' }),
PayDecrease: () => dispatch({ type: '扣工資' })
}
}
//連接組件
App = connect(mapStateToProps, mapDispatchToProps)(App)
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
我們可以看到杨箭,我們僅僅對(duì)代碼進(jìn)行了稍微的改造寞焙,在index.js里面寫(xiě)個(gè)APP組件以方便我們觀(guān)察,APP組件里面的button分別觸發(fā)不同的事件。
action啊 reducer啊 store啊 想必大家都已經(jīng)了解過(guò)了 這里不再做過(guò)多介紹捣郊。我們主要關(guān)注下哪里有變化:
首先最明顯的是demo中引入react-redux的Provider和connect辽狈,它們非常重要!這里先大概解釋下它們的作用:
Provider:它是react-redux 提供的一個(gè) React 組件呛牲,作用是把state傳給它的所有子組件刮萌,也就是說(shuō) 當(dāng)你用Provider傳入數(shù)據(jù)后 ,下面的所有子組件都可以共享數(shù)據(jù)娘扩,十分的方便着茸。
Provider的使用方法是:把Provider組件包裹在最外層的組件,如代碼所示畜侦,把整個(gè)APP組件給包裹住,然后在Provider里面把store傳過(guò)去躯保。注意:一定是在Provider中傳store旋膳,不能在A(yíng)PP組件中傳store。
connect:它是一個(gè)高階組件 所謂高階組件就是你給它傳入一個(gè)組件途事,它會(huì)給你返回新的加工后的組件验懊,注重用法倒簡(jiǎn)單,深究其原理就有點(diǎn)難度尸变。這里不做connect的深究义图,主要是學(xué)會(huì)它的用法,畢竟想要深究必須先會(huì)使用它召烂。首先它有四個(gè)參數(shù)([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])碱工,后面兩個(gè)參數(shù)可以不寫(xiě),不寫(xiě)的話(huà)它是有默認(rèn)值的奏夫。我們主要關(guān)注下前兩個(gè)參數(shù)mapStateToProps和mapDispatchToProps怕篷。
connect的使用方法是:把指定的state和指定的action與React組件連接起來(lái),后面括號(hào)里面寫(xiě)UI組件名酗昼。
除此之外demo中還多出了mapStateToProps mapDispatchToProps 他們又有什么作用呢廊谓?通俗一點(diǎn)講的話(huà)就是:
比如你在一個(gè)很深的UI組件里 當(dāng)你想要獲得store的數(shù)據(jù)就很麻煩。mapStateToProps就是告訴store你需要哪個(gè)state麻削,需要什么數(shù)據(jù)就直接在mapStateToProps中寫(xiě)出來(lái)蒸痹,然后store就會(huì)返回給你。同理呛哟,如果你想要dispatch派發(fā)一些行為怎么辦呢叠荠,mapDispatchToProps就是告訴store你要派發(fā)什么行為,需要派發(fā)什么行為就在mapDispatchToProps中寫(xiě)出來(lái)扫责,然后store就會(huì)把你想要派發(fā)的行為告訴reducer蝙叛,接下來(lái)大家都應(yīng)該知道了 reducer就會(huì)根據(jù)舊的state和action返回新的state。
好了 公给, 這時(shí)候我們npm start 打開(kāi)瀏覽器看一下有什么效果:
[圖片上傳失敗...(image-ce0bae-1576896111419)]
可以看到頁(yè)面上已經(jīng)有內(nèi)容借帘,多了一段文字和兩個(gè)按鈕蜘渣,當(dāng)我們點(diǎn)擊會(huì)有什么反應(yīng)呢?
[圖片上傳失敗...(image-7cedb5-1576896111419)]
果不其然肺然,當(dāng)我們點(diǎn)擊'升職加薪'按鈕時(shí)候 '當(dāng)月工資'也相應(yīng)的增加了蔫缸。我們捋一下整個(gè)事件流程:
1 點(diǎn)擊按鈕 2 觸發(fā)PayDecrease()方法 3 該方法派發(fā)相應(yīng)action 4 reducer根據(jù)action的type響應(yīng)得到新的state 5 通過(guò){this.props.tiger}拿到新的state 渲染到頁(yè)面
ok, 這個(gè)簡(jiǎn)單的demo我們就實(shí)現(xiàn)了际起。但是現(xiàn)在還有一個(gè)問(wèn)題:我們把所有的action reducer store Provider connect等等都寫(xiě)在了一個(gè)頁(yè)面拾碌,這在我們實(shí)際開(kāi)發(fā)中肯定是不合理的,所以街望,我們最后就給這個(gè)小demo再優(yōu)化下:
首先校翔,我們要把a(bǔ)ction,reducer什么的抽離出去灾前,作為一個(gè)單獨(dú)的文件防症,然后再導(dǎo)出:
src/index.reducer.js:
const tiger = 10000
//這是action
const increase = {
type: '漲工資'
}
const decrease = {
type: '扣工資'
}
//這是reducer
const reducer = (state = tiger, action) => {
switch (action.type) {
case '漲工資':
return state += 100;
case '扣工資':
return state -= 100;
default:
return state;
}
}
export default reducer
其次,我們也要把APP組件寫(xiě)在外面 (此處一定要注意: 導(dǎo)出的不是APP組件哎甲,而是connect后的APP組件)
src/APP.js:
import React, { Component } from 'react';
import { connect } from 'react-redux';
class App extends Component {
componentDidMount() {
console.log(this.props)
}
render() {
const { PayIncrease, PayDecrease } = this.props;
return (
<div className="App">
<h2>當(dāng)月工資為{this.props.tiger}</h2>
<button onClick={PayIncrease}>升職加薪</button>
<button onClick={PayDecrease}>遲到罰款</button>
</div>
);
}
}
//需要渲染什么數(shù)據(jù)
function mapStateToProps(state) {
return {
tiger: state
}
}
//需要觸發(fā)什么行為
function mapDispatchToProps(dispatch) {
return {
PayIncrease: () => dispatch({ type: '漲工資' }),
PayDecrease: () => dispatch({ type: '扣工資' })
}
}
export default App = connect(mapStateToProps, mapDispatchToProps)(App)
把這些東西分離出去之后蔫敲,此時(shí)的index.js看起來(lái)明顯就簡(jiǎn)潔了許多:
src/index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import reducer from './index.reducer'
//創(chuàng)建store
const store = createStore(reducer);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root'));
好了,比較基礎(chǔ)的redux和react-redux例子到這就結(jié)束了炭玫,感覺(jué)廢話(huà)有點(diǎn)多了奈嘿。。能看完的都是真愛(ài)吞加。裙犹。 哪有錯(cuò)誤 歡迎指正!