iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 3
0
自我挑戰組

玩轉 React 從0到1系列 第 18

【Day 18】React 關於 Redux

  • 分享至 

  • xImage
  •  

前言

在開始前要先說明,如果你的UI元件沒有很多、很複雜,沒有很多資料交互的溝通,那可以明確的跟你說:你並不需要Redux,不要為了用而用,你可能會因為加入Redux讓你的系統莫名的複雜很多。React 本身數據是單向流動而且不可逆的,像是父元件到子元件是靠 props 來做溝通,或是在子元件中要修改也要透過 setState 去處理;反之,當子元件要傳遞給父元件則需要去調用父元件的方法,但是一個元件可能有很多的 State,元件之間有時候會有互動,對於這麼多的 State 的維護其實是很雜亂的,那 Redux 就是為了解決這項問題。

Redux 是什麼?

Redux is a predictable state container for JavaScript apps.

這是官方給出的定義,以最白話的方式說,它是用來管理元件的公共 State 的容器(倉庫),當元件擁有很多的 State,而且元件之間需要共享 State 時,Redux 可以集中管理這些 State,而不需要透過一層一層的傳遞。Redux 是從 flux 延伸的,那它與 flux 最大的差別,就是它放棄了 dispatcher,不需要再去使用 Event Emitters,而是使用 Reducer 代替。

Redux 工作流程

https://ithelp.ithome.com.tw/upload/images/20201007/20109963ALGwhtDEuz.png

Store

Store 是用來保存 state 的地方,全部只能有一個 Store。

Store 在這裏的責任包含:

  1. 掌管所有狀態
  2. 提供藉由 dispatch(action) 來更新 State
  3. 提供 getState() 方法來取得 State
  4. 透過 subscribe(listener) 註冊 listener

Store 具有Redux 提供了 createStore 的函數來生成 Store

import { createStore } from 'redux';
const store = createStore(fn);

Action

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 Creator 就是用來生成 Action 這個 Object 的函數

const ADD_CONTEST_ARTICLE = '撰寫鐵人賽文章';

export function addContestArticle(text) {
  return {
    type: ADD_CONTEST_ARTICLE,
    text
  }
}

在這裡 addContestArticle 就是一個 Action Creator,有時候一個動作需要觸發多個 Action,就可以用 Action Creator 做組合。

Store.dispatch(action)

使用者經由跟頁面互動,會觸發到事件(像是點擊、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

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 設計原則

在 Redux 中有以下幾種設計原則:

單向數據流

這裏跟 props 不能被直接修改是一樣的道理,當父元件向子元件傳遞數據的時候通常是靠屬性去進行傳遞,而子元件則是通過 this.props 去接收,但外部傳遞進來的 props 不能直接修改,而是要透過 React setState() 方法進行觸發動作

唯一數據來源

這裡指的是元件所有的 State 應該要由 Store 統一保管,而早期的 Flux 是允許有多個 Store 的,而上面我們也強調了,整個 Redux 的專案應該只保持一個 Store,其實也可以把 Store 跟 Context 劃上等號(概念是一樣的)

保持狀態只讀

這裏如果要修改 Store 狀態,需要通過 dispatch Action 去觸發才行,不能直接去修改狀態;但如果頁面要進行渲染或更改,元件狀態是多少都會被變動的,如果不能變頁面也不會有新的變化,因此如果要完成頁面渲染,需要改變元件的狀態下,應該是要創建一個新的 State 返回給 Redux

數據變化只能透過 reducer(純函數) 完成

為什麼 Reducer 需要是一個純函數?純函數指的是 輸入/輸出的資料都是顯性的,代表函數與外界的溝通只有一個通道:參數 跟 傳回值,純函數是不能去存取外部變數的,純函數的好處就是可以避免一些副作用,所以 Reducer 也繼承了這項優點。Reducer函數在做的是就是根據 State 和 Action 去產生一個新的返回給 Store,它定義了元件該如何根據 Action 去更新 Store 的狀態

結論

  • 介紹了 Redux

/images/emoticon/emoticon08.gif


上一篇
【Day 17】React 中發送 Ajax 請求以及 Mock數據
下一篇
【Day 19】React 結合 Redux:react-redux 實作
系列文
玩轉 React 從0到130
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言