在開始前要先說明,如果你的UI元件沒有很多、很複雜,沒有很多資料交互的溝通,那可以明確的跟你說:你並不需要Redux
,不要為了用而用,你可能會因為加入Redux讓你的系統莫名的複雜很多。React 本身數據是單向流動而且不可逆的,像是父元件到子元件是靠 props 來做溝通,或是在子元件中要修改也要透過 setState 去處理;反之,當子元件要傳遞給父元件則需要去調用父元件的方法,但是一個元件可能有很多的 State,元件之間有時候會有互動,對於這麼多的 State 的維護其實是很雜亂的,那 Redux 就是為了解決這項問題。
Redux is a predictable state container for JavaScript apps.
這是官方給出的定義,以最白話的方式說,它是用來管理元件的公共 State 的容器(倉庫),當元件擁有很多的 State,而且元件之間需要共享 State 時,Redux 可以集中管理這些 State,而不需要透過一層一層的傳遞。Redux 是從 flux 延伸的,那它與 flux 最大的差別,就是它放棄了 dispatcher
,不需要再去使用 Event Emitters,而是使用 Reducer 代替。
Store 是用來保存 state 的地方,全部只能有一個 Store。
Store 在這裏的責任包含:
Store 具有Redux 提供了 createStore 的函數來生成 Store
import { createStore } from 'redux';
const store = createStore(fn);
Action 本質上是 Javascript 的 Object,而它也是 Store 資料的唯一來源,它會將 State 傳給 Store
Action 是一個 plain object
,其中 type 這個屬性是必須的,表示 Action 的名稱,也是用來傳遞要改變的類型,通常這裏都是常數,專案上也可以將所有 Action 集中檔案進行管理,除了 type 其他屬性則可以自由設置。
const action = {
type: 'ADD_CONTEST_ARTICLE',
payload: 'Learn_Redux_And_Write_Article',
}
上方程式中,Action 的名稱是 ADD_CONTEST_ARTICLE,它所包含的資料是 Learn_Redux_And_Write_Article 這個字串。
Action Creator 就是用來生成 Action 這個 Object 的函數
const ADD_CONTEST_ARTICLE = '撰寫鐵人賽文章';
export function addContestArticle(text) {
return {
type: ADD_CONTEST_ARTICLE,
text
}
}
在這裡 addContestArticle 就是一個 Action Creator,有時候一個動作需要觸發多個 Action,就可以用 Action Creator 做組合。
使用者經由跟頁面互動,會觸發到事件(像是點擊、Ajax),而在去呼叫 Store.dispatch(action) 這個方法,Store 則會拿著此時的 State(狀態) 跟 Action 給 Reducer 去做處理,更新 State
// 以上方 Action Creator 建置出來的 Action 為基礎,這裏可以這麼呼叫它
import { addContestArticle } from './actions';
store.dispatch(addContestArticle('Learn about store how to use'));
Reducer 是個純函數 (state, action) => state,描述了 Action 如何將 State 轉成下一個 State
以下為概念的程式碼:
const reducer = function(state, action) {
// ...
return new_state;
}
State 的初始值可以默認為 0,Reducer 函數在收到 ADD 的 Action 後,就返回一個加法後的 State
以下為程式碼:
const defaultState = 0;
const reducer = (state = defaultState, action) => {
switch (action.type) {
case: 'ADD_CONTEST_ARTICLE':
return state + action.number
default:
return state;
}
};
const state = reducer(1, {
type: 'ADD',
number: 2
})
實際中 Reducer 不用手動調用,而是 store.dispatch 觸發 Reducer 就會自動執行了
在 Redux 中有以下幾種設計原則:
這裏跟 props 不能被直接修改是一樣的道理,當父元件向子元件傳遞數據的時候通常是靠屬性去進行傳遞,而子元件則是通過 this.props 去接收,但外部傳遞進來的 props 不能直接修改,而是要透過 React setState() 方法進行觸發動作
這裡指的是元件所有的 State 應該要由 Store 統一保管,而早期的 Flux 是允許有多個 Store 的,而上面我們也強調了,整個 Redux 的專案應該只保持一個 Store,其實也可以把 Store 跟 Context 劃上等號(概念是一樣的)
這裏如果要修改 Store 狀態,需要通過 dispatch Action 去觸發才行,不能直接去修改狀態;但如果頁面要進行渲染或更改,元件狀態是多少都會被變動的,如果不能變頁面也不會有新的變化,因此如果要完成頁面渲染,需要改變元件的狀態下,應該是要創建一個新的 State 返回給 Redux
為什麼 Reducer 需要是一個純函數?純函數指的是 輸入/輸出的資料都是顯性的,代表函數與外界的溝通只有一個通道:參數 跟 傳回值,純函數是不能去存取外部變數的,純函數的好處就是可以避免一些副作用,所以 Reducer 也繼承了這項優點。Reducer函數在做的是就是根據 State 和 Action 去產生一個新的返回給 Store,它定義了元件該如何根據 Action 去更新 Store 的狀態