什麼是 Redux
Redux 是 JavaScript 的狀態容器,提供可預測化的管理,可以讓你構建一致化的應用,運行與不同的環境(客戶端、服務器、原生應用),並且易於測試。(個人理解:Redux 和 Vuex 很像)
優點:
- 可預測:始終有一個唯一的準確的數據源(single source of truth)就是 store,通過 actions 和 reduces 來保證整個應用狀態同步,做到絕不混亂
- 易維護:具備可預測的結果和嚴格的組織結構讓代碼更容易維護
- 易測試:編寫可測試代碼的首要準則是編寫可以僅做一件事並且獨立的小函數(single responsibility),Redux的代碼幾乎全部都是這樣的函數:短小·純粹·分離
什麼時候使用 Redux
- 某個組件的狀態,需要共享
- 某個數據需要在任何地方都可以拿到
- 一個組件需要改變全局狀態
- 一個組件需要改變另一個組件的狀態
也就是:在 多交互、多數據源 中可以考慮使用 redux。
Redux 的三個基本原則
- 單一數據源:整個應用的 state 被儲存在一棵 Object tree 中,並且這個 Object tree 只存在於唯一一個 store 中
- reducer:形式爲(state,action)=> state 的純函數,功能是提供action 來修改 state
- store:用於存儲 state,你可以把它看成一個容器,整個應用只能有一個 store
簡單來理解就是:在組件中共享的數據都存儲在 store 中,而 store 是隻讀的,我們只可以通過 reducer 來改變 store 中的數據
說太多的理論也沒多大用,先看一個簡單的 demo 吧
大概就這樣,沒寫樣式。
主要的功能就是當我點擊增加的話,就將文本框中值添加到下面的 ol 中,當我們點擊 ol 中的一項時,會刪除你點擊的那一項
你肯認爲很簡單,O(∩_∩)O哈哈~,這次我們使用redux,所有數據到會放到state 中的 store 中,這就簡單了。
好了,看下面的解析。
Redux 工作流程
如何改變數據呢?
看上圖所示:
- 首先我們會通過 ActionCreators 觸發給 Store ,而 Store 默默的把這個觸發交給了 Reducers
- Reducers 處理完結果後會將結果返回給 Store ,從而改變 Store ,這個時候我們必須使用 Store 的一個方法將我們改變的數據渲染到我要改變的組件上
安裝
先安裝 redux
npm install --save redux
使用
剛剛開始學習 redux,感覺比較怪異,好在多寫幾遍就好多了。
我使用了 create-react-app
幫我創建一個 react 項目(不用配置),如果沒安裝,使用進行安裝:
npm i create-react-app -g
目錄結構:
其中src/store
下文件都是一些使用 redux
的文件,src/App.js
這個文件中主要在這裏寫UI的
App.js 的代碼:
import React,{Component} from 'react';
import store from './store/store';
import {
addItem,
alertInputValue,
deleteItem
} from './store/actionCreator';
console.log(store);
class App extends Component{
constructor(props) {
super(props);
// 使用 store.getState() 來獲取倉庫中的數據
this.state = store.getState();
}
render() {
let {state} = this;
let {inputValue,list} = state;
// store.subscribe監聽 store 中數據改變,從而我們可以重新渲染數據
// 只要 store 中的數據發生改變,這個函數就會被觸發
store.subscribe(()=> {
const {inputValue,list} = store.getState();;
this.setState({
inputValue: inputValue,
list : list,
})
});
return (
<div className="App" style={{margin: '20px'}} >
<div>
<div>
<input
placeholder='請輸入數據'
style={{width: '300px'}}
value={inputValue}
onChange={(e) => {
store.dispatch(alertInputValue(e.target.value))
}}
/>
<button
type="primary"
style={{marginLeft:'36px'}}
onClick={() => {
store.dispatch(addItem(inputValue))
}}
>
{/* 當我們點擊增加按鈕的時候會 使用 store.dispatch 來觸發 reducer,而他會將 addItem(inputValue)返回的參數,傳遞給 action */}
{/* 而我們通過 reducer 中的 action 來判斷到底怎麼處理函數 */}
增加
</button>
</div>
<ol>
{list.map((item,index) => {
return (
<li key={index}
onClick={() => {
console.log(index);
store.dispatch(deleteItem(index))
}}
>
{item}
</li>
)
})}
</ol>
</div>
</div>
);
}
}
export default App;
以下都是 store 文件夾下的代碼:
store.js 的代碼:
/**
* 該文件主要是創建一個 store 對象,並將它默認導出
* 其中:createStore 的參數:
* 第一個:reducer 就是我們流程圖中的 Reducers
* 第二個:是 Chrome 下的一個查看、調試 redux 的工具
*/
import {createStore} from 'redux';
import reducer from './reducer';
export default createStore(
reducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
那個工具在哪下載呢?
先聲明:要知道怎麼科學上網
這個 “應用” 在左上角
進入到這個頁面
下載這個就行了
使用:
就看到我們的數據了
reducer.js 的代碼 :
/**
* 該文件導出一個函數:
* 函數的參數:
* state: 表示 store 中的存儲的數據(狀態)
* action: 通過 action 來改變 state 的數據
*/
import {
ADD_ITEM,
DELETE_ITEM,
ALERT_INPUTVALUE
} from './actionTypes';
let defaultState = {
inputValue : '請輸入東西',
list: [
'Racing car sprays burning fuel into crowd.',
'Japanese princess to wed commoner.',
'Australian walks 100km after outback crash.',
'Man charged over missing wedding girl.',
'Los Angeles battles huge wildfires.',
]
}
export default (state = defaultState,action) => {
let newState = JSON.parse(JSON.stringify(state));
switch (action.type) {
case ADD_ITEM:
newState.list.push(newState.inputValue);
newState.inputValue = '';
return newState;
case DELETE_ITEM:
newState.list.splice(action.index,1);
return newState;
case ALERT_INPUTVALUE:
newState.inputValue = action.text;
return newState;
}
return state;
}
actionTypes.js 的代碼:
/**
* 該文件導出都是一些常量:就是 actionCreators.js 文件要使用的常量
* 其實;直接在 actionCreators 中寫這些 字符串也行,
* 但是:當我們做一個大型的項目的時候,這樣做可以迅速的排錯,養成好習慣,增加代碼的可維護性
*/
export const ADD_ITEM = 'ADD_ITEM';
export const DELETE_ITEM = 'DELETE_ITEM';
export const ALERT_INPUTVALUE = 'ALERT_INPUTVALUE';
actionCreator.js 的代碼:
/**
* 導出的是一些對象:
* 例如:
* {
* type: ADD_ITEM,
* text: text,
* }
* 其中: type 主要是來區別,我們應該使用哪一種 reducer,配合 store.dispatch 函數來使用
*/
import {
ADD_ITEM,
ALERT_INPUTVALUE,
DELETE_ITEM
} from './actionTypes';
export const addItem = function(text) {
return {
type: ADD_ITEM,
text,
}
}
export const alertInputValue = function(text) {
return {
type: ALERT_INPUTVALUE,
text,
}
}
export const deleteItem = function(index) {
return {
type: DELETE_ITEM,
index,
}
}
大概就這樣把:感覺我也不是特別懂,主要是我也沒寫多少遍,這個還是要多多練習纔行,剛剛開始的時候,你肯定會感覺比較繞的,多敲幾遍,多想幾遍會好多的
這個僅僅只是 redux 最簡單的用法,還有什麼中間件,合併之類的。
參考資料:
- 《Redux 入門教程》(阮老師):http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_one_basic_usages.html
- 《Redux 中文文檔》:https://www.redux.org.cn/