EP10 | React 18 全家桶複習 - React-Redux

結合 react 的 redux 使用方法

  1. 下載 npm i react-redux

  2. 透過 react-redux 中的 Provider 注入 Redux 的狀態給組件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // ...引入其他模組
    import { Provider } from "react-redux";
    import store from "./01.redux/store";
    /* 1.透過 Provider 將 redux 儲存庫數據傳入到組件中 */
    root.render(
    <StrictMode>
    <Provider store={store}>
    <RouterProvider router={router} />
    </Provider>
    </StrictMode>
    );
  3. 在組件中透過 react-redux 提供的 connect()(組件名) 讓 redux 中 store 的 state 及 dispatch 與組件產生聯繫,無須再透過 store.subscribe() 方法訂閱 store 。]

注意: export 出去的要是經過 connect 後的組件。

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import { deleteTodo, getTodos } from "./01.redux/actions/todoAction";
import { connect } from "react-redux";
function Home({ todos, deleteTodo, getTodos }) {
// 4.redux 的狀態經過 conncect 後會透過 props 傳入
// const [todo, setTodo] = useState(store.getState());
const deleteItem = (item) => {
// 4. redux 的 dispatch 經過 conncect 處理後會透過 props 傳入
// store.dispatch(deleteTodo(item));
// setTodo(store.getState());
deleteTodo(item);
};

// 透過 react-redux 的 connect 取代
// store.subscribe(() => {
// console.log("@home訂閱的資料更新啦");
// setTodo(store.getState());
// });
useEffect(() => {
// 4.redux 的狀態經過 conncect 後會透過 props 傳入
//if (store.getState().length === 0) {
if (todos.length === 0) {
console.log("@home 發出數據請求");
// 4. redux 的 dispatch 經過 conncect 處理後會透過 props 傳入
// store.dispatch(getTodos());
getTodos();
} else {
console.log("@home緩存");
}
}, []);

return (
<div>
我是Home,放置所有 todo 資料
<hr />
{todos.map((item) => (
<li key={item.id}>
{item.title}
<button
onClick={(e) => {
deleteItem(item);
}}
>
刪除
</button>
</li>
))}
</div>
);
}

//3. connect(參數1: mapStateToProps, 參數2: mapDispatchToProps)
// mapStateToProps 是一個 function,可接收 redux 的state,對其執行代碼並返回要傳給 props 的值
const mapStateToProps = (state) => {
console.log("@mapStateToProps", state);
// 這個會返回給組件的 props
return {
todos: state
};
};

// mapDispatchToProps 也是一個 function,但可以直接簡化一個對象 {對象名: actionCreator名}
// 因為 react-redux 會自動幫其調用 bindActionCreators
// 當透過props調用對象名時,react-redux就會自動協助調用 dispatch(actionCreator名)
const mapDispatchToProps = {
// deleteTodo(傳入 props 的 dispatch 名): deleteTodo(引入的actionCreator名)
deleteTodo,
getTodos
};

// 2. 透過 connect 使得組件與 redux 發生關聯,並將 redux 儲存的狀態及 dispatch 傳給組件的 props
export default connect(mapStateToProps, mapDispatchToProps)(Home);

React-redux Hooks

  • useSelector() 取代使用 connect 中的 mapStateToProps: 如果值相同可以調用緩存結果(shallowEqual 會協助比較),不會重新調用。

  • useDispatch() 取代 connect 中的 mapDispatchToProps

透過 Hooks 就無需再去使用 connect 來將store 中的 state 及 dispatch 傳給組件的 props了

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
34
35
36
37
38
39
40
import { deleteTodo, getTodos } from "./01.redux/actions/todoAction";
import { shallowEqual, useSelector, useDispatch } from "react-redux";

export default function Home(props) {
// 1. useDispatch 取代了 connect 方法傳遞的 mapDispatchToProps
const dispatch = useDispatch();
// 2. useSelector 取代了 connect 方法傳遞的 mapStateToProps
const todos = useSelector((state) => state, shallowEqual);
const deleteItem = (item) => {
deleteTodo(item);
};

useEffect(() => {
if (todos.length === 0) {
console.log("@home 發出數據請求");
dispatch(getTodos());
} else {
console.log("@home緩存");
}
}, []);

return (
<div>
我是Home,放置所有 todo 資料
<hr />
{todos.map((item) => (
<li key={item.id}>
{item.title}
<button
onClick={(e) => {
deleteItem(item);
}}
>
刪除
</button>
</li>
))}
</div>
);
}