目錄

React + Redux 常見問題

React + Redux 常見問題

Q1: Flux Pattern 是什麼?

Flux Pattern 是一個單向資料流設計模式,React 中所有元件都建議採用,以單向資料流的概念避免產生 side effect

/2020/01/react-redux-faq/flux-pattern.jpg
由 React 渲染出view,使用者操作之後,發出第一個action,開始接下來的事

Q2: Redux 是什麼?

Redux 是一種 Flux Pattern 的實作,提供一些 function 讓開發者簡單完成 Flux pattern

以下為使用 Redux 時必須要知道的名詞:

  • store: 一個巨大 Object,存放元件狀態或資料

  • action: 一個 Object,通常具有 typepayload 兩個屬性。 type 用來區別是什麼動作,payload 則是資料或參數 { type: ‘xxx’, payload: {} }

  • reducer: 一個 function,接收參數為當下的 store 和 action,回傳新的store

  • dispatch: 一個 function,用來發送 action 物件到 reducer

  • actionCreator: 一個 function,用來產生複雜的 action

綜合前四點,想要改變 Store (狀態),只要透過dispatch function 發送 actioin 物件:

dispatch(action)

Q3: dispatch function 是從哪來 ?

react-redux 有提供幾種方法能直接取用 dispatch function ,或將其注入元件

  1. 透過 connect() 這個 hoc,可以把 dispatch 注入元件

  2. Function component 可以透過 react-redux 的 useDispatch() hook

  3. 非 react 的部分,可直接拿 configureStore 產生的物件, dispatch function 為其中的屬性之一

Q4: action creator 是什麼 ?

用來產生複雜的 action。

因為 action 不太可能單純只是一個常數,通常有一些 payload 需要組合

為了讓程式架構更乾淨,可透過 actionCreator 組合 action。

(action creator不介入redux運作)

Q5: dispatch 該在哪邊使用 ?

  1. 從 View Component

  2. action creator (下面會提到redux-thunk)

  3. 外部 (透過 configureStore 取得 dispatch function)

Q6: 可以不經由 dispatch,直接呼叫 actionCreator 嗎 ?

1
2
3
4
// 不行,通通要拿去做雞精
import { setIsRootPanel } from ./actionCreator;然後setIsRootPanel() ?*

setIsRootPanel()

❌ 呼叫 setIsRootPanel() 之後,你只是得到了一個 action,只是個物件

Q7: actionCreator 參數中的 dispatch 是哪裡來 ?

常看到有人這麼寫:

1
2
3
export const setIsRootPanel = () => (dispatch, getState) => {
  dispatch({  });
}

Redux-thunk

redux-thunk 是 redux middleware,安插在 redux 流程中間,讓原生只支援物件的 action,也支援 function,開發者可以在此 function 中做更多處理。

其原理是,只要偵測到 actionfunction,會自動把 dispatch, getState 兩個函式當成參數丟進去

所以,dispatch( () =>{} ),原本 redux 不支援,但使用 redux-thunk 後,會多塞兩個參數進去,讓開發者拿來用

1
2
3
4
5
6
7
// 原本 action 只支援物件
dispatch({type: "", payload: ""})

// 使用 thunk 後,也支援 function ,並會注入 dispatch 和 getState 作為參數
dispatch(
  (dispatch, getState) => {}
)

意思就是 dispatch了一個型別是函式的 action

把 (dispatch, getState) => {} 這個 action 抽離出來,用 acion creator 產生,就變成上面的樣子了

但是! action creator 回傳的東西是一個 type = function 的 action

直接呼叫 setIsRootPanel(),只會得到一個 function (dispatch, getState) {} ,不會發生任何事情

還是必須透過 dispatch 去發,dispatch(setIsRootPanel())

非同步 dispatch 用法,可以參考另外這篇

Q8: 有快速綁定 dispatch 的方法嗎?每次 mapDispatchToProps 都寫一大串!

  1. 元件中用 bindActionCreator

  2. connect 時一次綁全部,缺點是可讀性差,不知道綁了哪些

1
2
3
4
    import * as **actions** from './actionCreator'
    **const mapDispatchToProps** = {
      **...actions**,
    };
  1. 寫 functional component,用useDispatch hook,只取需要的action creator來使用

我個人比較喜歡 function component,就都使用 useDispatch

順便推崇一下 function component 的幾個好處

  1. Functional component 可讀性較佳,且較容易單元測試

  2. hook 很直覺,不用寫一堆生命週期,寫起來 code 可能比較少

  3. 使用 Functional Component 比較能幫助開發者符合 react 的設計模式與資料流,減少元件中 state 的使用,較容易區分 Container 元件和 Presentation 元件

  4. React team 說 Functional 的效能比較好,未來會針對 Functional Component 優化

方法很多,沒有最好的 pattern

但畢竟專案會越長越大,可讀性好將來還是比較好維護

貪圖一時方便,使用奇技淫巧簡化一些東西,無形之中累積的技術債是很可怕的