書接上回 《redux懶人教程》,咱們已經學會了使用redux管理混亂的全局狀態,下面咱們一塊兒看看redux是怎麼幫助咱們管理react應用的狀態的。前端
咱們先捋一捋react的一些基礎概念,看看在什麼狀況下咱們才須要引入redux。react
react這樣的前端框架的功能一言歸納就是實現了數據和UI的實時映射。開發者只須要經過react組件管理數據,當數據變化時,react會讓其映射的UI實時更新。而組件的數據主要是兩個:state和props。props是父組件傳遞過來的數據,state是組件自身管理的數據,它又以props的形式傳遞給子組件。一個組件的props和state的變化都會引起該組件及其子組件對應UI的變化,也就是重渲染。 redux
props更像數據管道,state則比較像數據引擎。api
如今問題來了,組件4和組件7之間要怎麼通訊呢。全體起立,讓咱們再次大聲喊出這一句:數組
在計算機領域,若是有什麼事是加一層中間層解決不了的,那就加兩層bash
只須要把組件4和組件7須要通訊的數據提高到組件1上做爲組件1的state來管理,再經過props層層傳遞給組件4和組件7就好了。 OK,如今組件樹只有三層,經過這樣的方式或許還能夠接受,可是當組件樹有不少層的時候,你豈不是得寫不少次這樣的props傳遞的邏輯,這實在是太過辛苦而不優雅的一件事情了。所以,咱們也須要引入一個相似全局變量的東西,而react提供的context就是這個全局變量,它容許底層組件直接跨過中間組件,讀取頂層組件的數據,像這樣: 前端框架
結合以前的內容,咱們明確:框架
那麼如今你應該能解答這個這個靈魂之問了:要把redux裝進react,總共分幾步?ide
答:三步:函數
咱們延續上一篇文章中管理一個數組的例子:
第一步,咱們已經完成了:
import { createStore } from 'redux';
const initState = [];
const reducer = (state = initState, action) => {
switch(action.type) {
case 'add':
return [...state, action.addedItem];
case 'delete':
return [...state.slice(0, action.deletedIndex), ...state.slice(action.deletedIndex + 1)];
case 'clear':
return []
default:
return state;
}
};
const store = createStore(reducer);
複製代碼
第二步,把store放進頂層組件的context中,這個頂層組件就是react-redux中的Provider組件:
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import App from './App.js';
const initState = [];
const reducer = (state = initState, action) => {
switch(action.type) {
case 'add':
return [...state, action.addedItem];
case 'delete':
return [...state.slice(0, action.deletedIndex), ...state.slice(action.deletedIndex + 1)];
case 'clear':
return []
default:
return state;
}
};
const store = createStore(reducer);
ReactDOM.render(<Provider store={store}>
<App />
</Provider>,
document.getElementById('root');
複製代碼
第三步,底層組件從context中取出store對狀態進行讀寫。完成這一步時react-redux又把這個底層組件細分紅一父一子兩個組件,首先由一個父組件專門負責從context中取出store,把store管理的頂層狀態放在本身的數據引擎state中,用store.subcribe監聽頂層狀態的變化,頂層狀態一改變,這個父組件的數據引擎state就跟着改變,而後再把數據經過管道props傳遞給子組件。髒活累活都被父組件幹了,咱們開發子組件的時候只須要享用父組件傳遞過來的props就行了,真是父愛如山啊。另外,對頂層狀態進行操做的函數dispatch也須要經過props傳遞給子組件,這樣子組件才能夠修改頂層狀態嘛。思路已經理通了,react-redux還要作最後一點優化——由於父組件徹底不必直接把store管理的狀態整個傳給子組件,也不必把dispatch函數自己傳遞給子組件。假設頂層組件管理了100多個狀態,而實際上你在開發的底層組件可能只想讀寫其中的一個狀態而已——好比這個狀態叫theme,那麼我但願我寫底層組件時,徹底不用管其餘狀態是什麼,也不用管要修改其餘狀態須要dispatch什麼action,我只想經過props.theme讀狀態,經過props.setTheme()寫狀態。嗨呀其實這不就是加一箇中間層就能搞定的事嗎,而react-redux須要你寫的mapStateToProps函數和mapDispatchToProps函數就是專門用來幹這個的。
好了囉裏囉嗦一大堆,上面的這一段是告訴你要完成第三步都須要作什麼,這其中像從context中取出store這種又髒又累的重複性工做,已經被react-redux在connect這個高階組件中作完了。所謂高階組件,其實就是一個函數,傳給它一個組件,它返回一個新的組件。在connect這個高階組件中,你須要傳給他mapStateToProps,mapDispatchToProps以及你的業務子組件,它返回給你一個能讀寫store管理的狀態的組件。
talk is cheap, show you the code好伐:
import React from 'react';
import {connect} from 'react-redux';
const mapStateToProps = (state) => {
return {
array: state
}
};
const mapDispatchToProps = (dispatch) => {
return {
addItem: (item) => {
dispatch({
action: 'add',
addedItem: item
});
}
}
};
const App = (props) => {
return (
<div>
<div>{props.array}</div>
<div>
<button onClick = {props.addItem(1)}>在數組中添加一個1</button>
<div>
<div>
)
};
export default connect(mapStateToProps, mapDispatchToProps)(App);
複製代碼
最後,把react-redux的使用方法用下面這個圖歸納一下:
好了,到如今爲止redux的懶人教程系列就算完結了,筆者在寫的過程當中一直極力避免去詳細解析API的具體用法,或者太過深刻地解釋原理,主要是但願能幫助讀者花比較小的代價就能大體理解爲何要用redux/react-redux, 怎麼用redux/react-redux。 redux的主要生態是其豐富的中間件,也有實現類似功能的狀態管理工具mobx能夠學習,在react-hook風頭正盛之際,react-redux也提供了對應的hook api,在此就再也不一一介紹了,搞懂redux核心用法以後上手這些都會很快的。
水平有限,有哪些寫的不清不楚或者表述不正確的地方歡迎多交流指正,以爲有幫助的話求一個贊哦 :)