React作為一套優(yōu)秀的前端框架,為我們提供了一套十分優(yōu)秀的頁面構(gòu)建方法和思想∏渫拢可是,React還只是一套視圖構(gòu)建框架锋华,在軟件設(shè)計(jì)模塊里面還只是MVC的View層嗡官,涉及數(shù)據(jù)模型時(shí)需要一些其他框架的輔助。其中毯焕,最著名的莫過于Redux了衍腥。既然是結(jié)合React使用Redux,那么前端大爺假設(shè)你已經(jīng)使用過React框架纳猫,對React有一定的了解了紧阔,并且大概知道action, reducer, dispatch的關(guān)系,否則請先移步其他書籍文檔续担,因?yàn)闊o論如何15分鐘內(nèi)不可能從不會(huì)走到學(xué)會(huì)跑。
-----------------------------------分割線 0 分鐘---------------------------------
先解釋原理
首先活孩,React組件有state, props沒錯(cuò)吧物遇。state是內(nèi)部的狀態(tài),props是父組件傳進(jìn)來的屬性,state, props變化了要觸發(fā)react diff并且調(diào)用render方法更新組件询兴,同意吧乃沙。好,就是這么簡單的react基本原理诗舰,告訴我們除了用戶交互導(dǎo)致內(nèi)部state變化外警儒,數(shù)據(jù)流是從父組件通過props流向子組件導(dǎo)致子組件更新。這就是React的單向數(shù)據(jù)流:
自頂向下單向數(shù)據(jù)流眶根!
自頂向下單向數(shù)據(jù)流蜀铲!
自頂向下單向數(shù)據(jù)流!
重要的事情說三遍属百。
假設(shè)我們的app入口是這樣的:
ReactDOM.render(
<App />
document.getElementById('root')
);
這個(gè)App也是一個(gè)React組件记劝,它是我們的項(xiàng)目中居于最頂層的父組件。如果我們有某個(gè)組件族扰,他能夠提供數(shù)據(jù)源厌丑,而又居于App之上,那么數(shù)據(jù)就可以源源不斷的從它往下流到App以及各級子孫節(jié)點(diǎn)上去渔呵。所以Redux給我們提供了Provider:
import { Provider } from 'react-redux'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
-----------------------------------分割線 5 分鐘---------------------------------
Provider接受一個(gè)屬性store怒竿,這就是我們?nèi)值臄?shù)據(jù)store。我們要根據(jù)reducer函數(shù)來創(chuàng)建它扩氢。
import { createStore } from 'redux'
import { combineReducers } from 'redux'
//reducer函數(shù)接受兩個(gè)參數(shù)耕驰,state和action,state帶默認(rèn)的初始值
function reducer1(state = [], action) {
switch(action.type) {
case 'add':
return [...state, 'apple is very delicious']; // 這里一定要返回一個(gè)新的數(shù)組类茂,而不能寫成state.push('apple is very delicious1');
default :
return state;
}
}
//reducer當(dāng)然可以定義多個(gè)耍属,不同的reducer對應(yīng)著不同的state對象,上面的reducer1操作一個(gè)數(shù)組對象巩检,這個(gè)reducer2操作一個(gè)Number類型state
function reducer2(state = 0, action) {
switch(action.type) {
case 'increase' :
++state;
return state;
default:
return state;
}
}
const reducer = combineReducers({
reducer1,
reducer2
})
var store = createStore(reducer);
store生成了厚骗,隨時(shí)可以通過store.getState()獲得當(dāng)前store的值。初始狀態(tài)下調(diào)用getState()獲得的返回值是
{reducer1: [], reducer2: 0}兢哭。
看领舰,reducer函數(shù)的名字對應(yīng)著store里面state的名字。
為了幫助初學(xué)者學(xué)習(xí)迟螺,可以添加以下語句冲秽,監(jiān)聽每一次dispatch操作后store的狀態(tài):
store.subscribe(()=>{
console.log(store.getState());
})
-----------------------------------分割線 10 分鐘---------------------------------
現(xiàn)在我們有了最高級別的Provider,并定義好了reducers, 傳入了store矩父。接下來我們該考慮子組件了锉桑。子組件長什么樣,要靠父組件給的props決定窍株,可是數(shù)據(jù)都在最高級別的provider store里面民轴,怎么樣把store里面的數(shù)據(jù)拿出來作為props給子組件呢9ツ!后裸?瑰钮?
react-redux給我們提供了魔法黑科技:mapStateToProps和mapDispatchToProps。
顧名思義微驶,把state和dispatch從store里面拿出來浪谴,作為props傳給子組件!
const mapStateToProps = state => {
return {
state1: state.reducer1
}
}
const mapDispatchToProps = dispatch => {
return {
add: () => {
dispatch({
type:'add'
})
}
}
}
class AppView extends Component {
render() {
const list = this.props.state1.map(v=>{
return (<p className="App-intro">{v}</p>)
})
return (
<div className="App">
<p>{list.length}</p>
{
list
}
<button onClick={()=>this.props.add()}>add</button>
</div>
);
}
}
const App = connect(
mapStateToProps,
mapDispatchToProps
)(AppView)
export default App;
看到了嗎因苹,經(jīng)過mapStateToProps和mapDispatchToProps處理后苟耻,我們直接在子組件AppView里面使用this.props.state1就可以拿到store里面的數(shù)據(jù),直接使用this.props.add就可以dispatch相應(yīng)的action容燕。store變化后視圖的更新是自動(dòng)的梁呈,無需手工干預(yù)。
源代碼見:https://github.com/myairforce1/simpleReduxDemo
看到這你是不是對在React中使用Redux有點(diǎn)感覺了呢蘸秘?請?jiān)彵疚氖褂昧艘粋€(gè)極為簡陋的例子官卡。本著老少咸宜,童叟無欺的初衷醋虏,我盡量搬上來一個(gè)功能少寻咒,但是好理解的例子。如果的確幫助到您颈嚼,請留下您對本文的喜愛毛秘。