redux+react-redux+示例的快速上手體驗
本文主要記錄下自己在react道路上的爬坑過程 以及對于剛學(xué)習(xí)redux的同學(xué)提供一些可供參考的例子。
之前用vue用了很久 vue的語法糖用起來是真的舒服 不過現(xiàn)在公司項目用的是react 只好默默的從vue轉(zhuǎn)到react 其實畢竟他們都是類似的框架, 雖然語法大不同, 但是有些地方的思想還是很像的, 廢話不多說了,開始正文...
本文主要分為兩個部分:redux和react-redux。 首先大概過一下redux的基礎(chǔ)部分:
1.redux
要知道redux和react并沒有半毛錢的關(guān)系,redux甚至可以和jq一起用。 react-redux才是react的用于便捷操作redux的第三方插件。所以呢,學(xué)習(xí)react-redux之前我們要比較熟悉的了解redux的思想。本文比較直接,不來虛的,直接上代碼:
首先就很熟悉了
1 使用官方腳手架
create-react-app redux-demo
2 環(huán)境搭建好之后 繼續(xù)安裝redux
npm install redux --S
進(jìn)入到項目文件夾 把我們用不到的全咔咔刪掉
在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();
這里大概解釋下每個的意思:
action:行為 它是一個對象 里面必有type來指定其類型 這個類型可以理解為你要做什么,reducer要根據(jù)action的type來返回不同的state 每個項目有且可以有多個action
reducer: 可以理解為一個專門處理state的工廠 給他一個舊數(shù)據(jù)它會根據(jù)不同action.type返回新的數(shù)據(jù) 也就是:舊state + action = 新state 每個項目有且可以有多個reducer
store: store本質(zhì)上是一個狀態(tài)樹,保存了所有對象的狀態(tài)。任何UI組件都能直接的從store訪問特定對象的狀態(tài)。每個項目有且只能有一個store
腦子里有了這些基本的概念后我們就可以把reducer放到createStore里并創(chuàng)建好store了
可以看到 代碼的最后我們打印了store.getState() 這段代碼簡單理解就是打印下store里的數(shù)據(jù)
因為我們只是寫了action并沒有給它dispatch 所以reducer只會走默認(rèn)的default 所以僅僅是返回state=tiger 那么tiger就是我們之前定義好的state
此時我們npm start 在瀏覽器打開該demo f12打開控制臺 可以看到打印的數(shù)據(jù)為:10000
這里我們只是簡單的回顧下redux的基礎(chǔ)知識 并沒有在app.js里面寫任何東西
好 可以看到在上面我們雖然定義了action 但是好像并沒有什么用?。?接下來我們要做的事情就是讓它變化了。
剛才僅僅是獲得到初始的數(shù)據(jù) 這并不是我們想要的結(jié)果 在實際項目中我們肯定有很多的需求 不同需求對應(yīng)不同功能 不同功能獲得不同數(shù)據(jù),所以接下來我們要用到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 也就是說reducer根據(jù)dispatch派發(fā)的action的type,return了新的state。當(dāng)然我們也可以派發(fā)store.dispatch(decrease) 那打印的結(jié)果就是 10000,原因想必大家都知道。
其實我們僅僅是多寫了store.dispatch(increase) 和 store.subscribe(() =>{}) 他們的每個作用大概解釋下:
dispatch的作用就是告訴reducer 我給你action, 你要根據(jù)我的action.type返回新的state。 然后reducer就會根據(jù)action的type,返回新的state。
我們給它dispatch了action,reducer也做出相應(yīng) 最后也返回新的state 但是其實這時候console.log()不會打印新的數(shù)據(jù) 因為state雖然變化了 但是還是打印store.getState()還是原始的數(shù)據(jù)
這時候我們就需要store.subscribe(() =>{})了 它的作用就是每當(dāng)reducer返回新的數(shù)據(jù) 它就會自動更新頁面 把UI組件的state更新下 不然的話 雖然state變化了 頁面仍不會更新(雖然現(xiàn)在還沒有其他組件)
2.react-redux
好了, 這些就是基本的redux的知識。我們不難發(fā)現(xiàn),這樣其實挺麻煩的。你需要寫好多好多東西,而且我們并沒有把reducer,action什么的給分離出去,不然的話我還要往很多組件里面?zhèn)骱芏鄸|西。這對我們實際開發(fā)是很不友好的。
所以, 這時候就十分迫切需要react-redux了。它的作用是幫助我們操作redux。有了它我們可以很方便的寫redux。接下來上代碼:
首先安裝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')
)
我們可以看到,我們僅僅對代碼進(jìn)行了稍微的改造,在index.js里面寫個APP組件以方便我們觀察,APP組件里面的button分別觸發(fā)不同的事件。
action啊 reducer啊 store啊 想必大家都已經(jīng)了解過了 這里不再做過多介紹。我們主要關(guān)注下哪里有變化:
首先最明顯的是demo中引入react-redux的Provider和connect,它們非常重要!這里先大概解釋下它們的作用:
Provider:它是react-redux 提供的一個 React 組件,作用是把state傳給它的所有子組件,也就是說 當(dāng)你用Provider傳入數(shù)據(jù)后 ,下面的所有子組件都可以共享數(shù)據(jù),十分的方便。
Provider的使用方法是:把Provider組件包裹在最外層的組件,如代碼所示,把整個APP組件給包裹住,然后在Provider里面把store傳過去。注意:一定是在Provider中傳store,不能在APP組件中傳store。
connect:它是一個高階組件 所謂高階組件就是你給它傳入一個組件,它會給你返回新的加工后的組件,注重用法倒簡單,深究其原理就有點難度。這里不做connect的深究,主要是學(xué)會它的用法,畢竟想要深究必須先會使用它。首先它有四個參數(shù)([mapStateToProps], [mapDispatchToProps], [mergeProps], [options]),后面兩個參數(shù)可以不寫,不寫的話它是有默認(rèn)值的。我們主要關(guān)注下前兩個參數(shù)mapStateToProps和mapDispatchToProps。
connect的使用方法是:把指定的state和指定的action與React組件連接起來,后面括號里面寫UI組件名。
除此之外demo中還多出了mapStateToProps mapDispatchToProps 他們又有什么作用呢?通俗一點講的話就是:
比如你在一個很深的UI組件里 當(dāng)你想要獲得store的數(shù)據(jù)就很麻煩。mapStateToProps就是告訴store你需要哪個state,需要什么數(shù)據(jù)就直接在mapStateToProps中寫出來,然后store就會返回給你。同理,如果你想要dispatch派發(fā)一些行為怎么辦呢,mapDispatchToProps就是告訴store你要派發(fā)什么行為,需要派發(fā)什么行為就在mapDispatchToProps中寫出來,然后store就會把你想要派發(fā)的行為告訴reducer,接下來大家都應(yīng)該知道了 reducer就會根據(jù)舊的state和action返回新的state。
好了 , 這時候我們npm start 打開瀏覽器看一下有什么效果:
[圖片上傳失敗...(image-ce0bae-1576896111419)]
可以看到頁面上已經(jīng)有內(nèi)容,多了一段文字和兩個按鈕,當(dāng)我們點擊會有什么反應(yīng)呢?
[圖片上傳失敗...(image-7cedb5-1576896111419)]
果不其然,當(dāng)我們點擊'升職加薪'按鈕時候 '當(dāng)月工資'也相應(yīng)的增加了。我們捋一下整個事件流程:
1 點擊按鈕 2 觸發(fā)PayDecrease()方法 3 該方法派發(fā)相應(yīng)action 4 reducer根據(jù)action的type響應(yīng)得到新的state 5 通過{this.props.tiger}拿到新的state 渲染到頁面
ok, 這個簡單的demo我們就實現(xiàn)了。但是現(xiàn)在還有一個問題:我們把所有的action reducer store Provider connect等等都寫在了一個頁面,這在我們實際開發(fā)中肯定是不合理的,所以,我們最后就給這個小demo再優(yōu)化下:
首先,我們要把action,reducer什么的抽離出去,作為一個單獨的文件,然后再導(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組件寫在外面 (此處一定要注意: 導(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)
把這些東西分離出去之后,此時的index.js看起來明顯就簡潔了許多:
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é)束了,感覺廢話有點多了。。能看完的都是真愛。。 哪有錯誤 歡迎指正!