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

一個最常見的作法。

簡述

雖然說你也可以自己手動把 Redux 跟 React 給串起來,但透過套件來處理會更好。這邊會介紹一套叫做 react-redux 的 library,用它來把 React 跟 Redux 串接起來。

記得,redux 跟 react-redux 是不同的東西:

  • Redux 是管理狀態的 library
  • react-redux 是用來把 React 跟 redux 結合起來的 library

不要再搞混啦!

要用 react-redux 的方式 有兩種,一種是建立 create-react-app 時加上參數:

1
npx create-react-app my-app --template redux

一種是對現有的 create-react-app 來加上 react-redux:

1
2
npm install redux 
npm install react-redux

我們要介紹的是第二種。

基本的資料夾結構

在串接之前記得先做好 redux 前置作業,你的資料夾結構應該會長成這樣:

  • redux
    • reducers
      • todos.js
      • users.js
      • index.js (把所有 reducer 集合起來)
    • store.js(負責建立 store)
    • actionTypes.js(把 action type 的常數集合起來)
    • actions(action creator 管理)
    • selectors(把選出 state 的 function 集合起來)

這邊列出我覺得需要知道一下內容的幾個檔案:

1. reducers/index.js

1
2
3
4
5
6
7
8
9
import { combineReducers } from "redux";
import todosReducer from "./todos"
import usersReducer from "./users"

// 把要 export 出去的 reducer 傳進去
export default combineReducers({
todosReducer,
usersReducer
})

這邊因為是「多個」reducer,所以資料結構會跟只有「單一個」的時候不太一樣,要多注意一下。

單一個的時候:

1
2
const store = createStore(todosReducer);
console.log(store.getState());

output:

1
2
3
{
todos: ['todo1', 'todo2', 'todo3']
}

多個的時候:

1
2
const store = createStore(todosReducer);
console.log(store.getState());

output:

1
2
3
4
5
6
7
8
{
todosReducer: {
todos: ['todo1', 'todo2']
},
usersReducer: {
users: ['user1', 'user2']
}
}

2. redux/store.js

1
2
3
4
5
import { createStore } from "redux";
import rootReducer from "./reducers";

// 把 reducer 丟進去 create 一個 store
export default createStore(rootReducer);

3. redux/selectors.js

這邊做個補充,selector 的用途只是「把我想要的 state 選出來」而已,畢竟你應該不會想在一個 Component 裡面拿到所有的 state,所以才會衍伸出這個東西。

另外之所以會抽出去建立成 constant 只是因為 code 寫起來會比較簡潔而已。

1
2
3
// 兩個 function
export const selectTodos = state => state.todosReducer.todos;
export const selectUsers = state => state.usersReducer.users;

其他的就只是把原本的東西抽出去寫成一個檔案而已,忘記的話可以參考:初探 Redux

正式串接

這邊寫個懶人包:

  1. 定義 Provider
  2. store 傳入 Provider,讓底下所有元件能夠接收
  3. 在元件內使用 useSelector 取出需要的 state(搭配前面寫好的 selectors.js)
  4. 先引入 useDispatch,接著就能透過 dispatch 發出 action

這邊直接附上 code,你邊看邊想一下應該就懂了:

1
2
3
4
5
6
7
8
9
10
// index.js
import { Provider } from "react-redux";
import store from "./redux/store"

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<Provider store={store}>
<App />
</Provider>
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// App.js
import { useState, useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { selectTodos } from "./redux/selectors"
import { addTodo } from "./redux/actions"

function App() {
const [value, setValue] = useState("");
// 用 useSelector 把 todos 的 state 拿出來
const todos = useSelector(selectTodos);
// 定義用來發出 dispatch 的 function
const dispatch = useDispatch();

// 表單 submit 後 disptch 新增 todo 的 action
const handleSubmit = e => {
e.preventDefault();
dispatch(addTodo(value));
setValue("")
}

return (
<div className="App">
<form onSubmit={handleSubmit}>
<input value={value} onChange={e => setValue(e.target.value)} />
</form>
<ul>
{todos.map(todo => <li key={todo.id} data-id={todo.id} >{todo.name}</li>)}
</ul>
</div>
);
}

export default App;

這樣子其實就串好囉!有疑問的話也可以去我寫的 範例 參考。

使用 redux-devtool 的小提醒 mentor-program-day130
Your browser is out-of-date!

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

×