用 react-redux 把 redux 跟 React 串接起來(Connect 版本)

早期的方法,雖然麻煩但也有一些好處。

簡述

用 react redux 串接 redux 的方法有兩種:

目前都會推薦用 hook 的方式來串,但建議還是能了解一下 connect 的做法是怎麼做的。

正文

它背後的原理其實就是「把 store 的東西當作 props 傳到 component 裡面」,我框起來的地方是重點,一定要看懂。

這種作法稱為:

HOC Higher Order Component,意思就是 Component 在包一層 Component

總而言之寫起來會長這樣(先看個大概就好,看不懂沒關係):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import TodoInput from "../components/TodoInput";
import { connect } from "react-redux";
import { addTodo } from "../redux/actions";

// 這兩個 function 下面會在解釋
const mapStateToProps = store => {
return {
todos: store.todosReducer.todos
}
};
const mapDispatchToProps = dispatch => {
return {
addTodo: payload => dispatch(addTodo(payload))
}
}

// 在 connect 傳入兩個 function,拿到 store 裡面的東西
const connectToStore = connect(mapStateToProps, mapDispatchToProps);
// 把 TodoInput 這個 Component 傳給 connectToStore
// 它會產生一個新的 Component
const connectTodoInput = connectToStore(TodoInput)
// 最後把新的 Component 輸出
export default connectTodoInput;

在解釋這段 code 以前先打個岔。

還記得剛剛說的嗎? connect 的原理只是多包一層 Component 而已,所以關於 Component 其實還可以分成下面這兩個東西:

  • dump / presentational Component
  • smart / container Component

那個負責接收 props 的 Component 就叫做 dump component,因為它完全不知道 redux 的存在,它只知道「哦,我會接收到 props,我用就對了」。

而那個負責把 store 傳下去的 Component 就是 smart component,因為它知道 redux 的存在,不像 dump component 純粹只管理 UI 的顯示。

所以這時候呢,資料夾的結構通常會長成這樣子:

  • containers
    • todoInput.js(dump Component)
  • components
    • todoInput.js(smart Component)

雖然只看名字的話感覺是一樣的東西,但它背後卻有著 dump 跟 smart 的區別。

這個想法是 Redux 的作者 Dan Abramov 提出的,有興趣的話推薦去看這篇文章:Presentational and Container Components

好,讓我們回來解釋 code 的部分吧。

首先 connect 只是個用來跟 store 串接起來的函式,它會接收兩個參數(function):

1. mapStateToProps

1
2
3
4
5
const mapStateToProps = store => {
return {
todos: store.todosReducer.todos
}
};

useSelector 是差不多的概念,就是「從 store 把想要的 state 選出來」,然後 return,它就會被當成 Props 傳入(它的函式命名我覺得有夠貼切)。

2. mapDispatchToProps

1
2
3
4
5
const mapDispatchToProps = dispatch => {
return {
addTodo: payload => dispatch(addTodo(payload))
}
}

我是這樣理解啦,你可以先思考這個問題,「現在沒有 useDispatch 能用了,那原本的 Component 要怎麼 dispatch 一個 action?」

剛剛不是有說可以傳 props 嗎?所以只要先在外面這一層把 dispatch 寫好後在當作 props 傳進去就好啦,這就是這一段在做的事情。

順道一提,這邊如果 props 跟 dispatch 的 action 同名,可以用這樣來縮寫:

1
2
3
const mapDispatchToProps = {
addTodo
}

做好以後,最後一步就是把 container/ 底下的 Component 引入使用而已。因為 code 有點多我就不貼這邊了,想看完整的原始碼到這邊來看。

最後只是想提一下,這樣子的做法有什麼好處嗎?

有哦!好處是「測試」比較好測,因為把 Component 都拆成更小的單位了,而且每個 Component 的職責更加分明(負責 UI / 負責 Redux),所以會要測試的項目會單純許多。

用 Redux-toolkit 串接 React 和 Redux 使用 redux-devtool 的小提醒
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×