React 與 Redux
React 與 Redux
React 是一個用於構建用戶界面的庫,而 Redux 是一個預測性狀態管理工具,適合處理大型應用中的全局狀態。在大型 React 應用中,組件之間的狀態共享變得複雜,這時候 Redux 就能夠很好地管理整個應用的狀態。
Redux 提供了一個全局的 store,應用的所有狀態都存儲在這個 store 中,並通過 actions 和 reducers 來管理狀態變化。
1. Redux 基本概念
在開始使用 Redux 前,我們需要了解其核心概念:
- Store:存放應用所有狀態的單一來源。它是一個 JavaScript 對象。
- Action:一個普通的 JavaScript 對象,用來描述要發生的事件。每個 action 必須有一個
type
屬性,表示這個行為的類型。 - Reducer:一個純函數,接收當前的狀態和 action,然後返回新的狀態。它是更新 store 的唯一方式。
- Dispatch:執行
action
的方法,調用它會觸發 reducer,從而改變 store 中的狀態。 - Selector:用於從 store 中獲取狀態的函數。
2. 安裝 Redux 和 React-Redux
在 React 應用中整合 Redux,需要安裝 redux
和 react-redux
:
1
npm install redux react-redux
3. 創建 Redux Store
首先,我們需要創建一個 Redux store。讓我們從定義一個 reducer 開始,然後將其應用到 store。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// counterReducer.js
const initialState = {
count: 0
};
function counterReducer(state = initialState, action) {
switch (action.type) {
case 'INCREMENT':
return {
...state,
count: state.count + 1
};
case 'DECREMENT':
return {
...state,
count: state.count - 1
};
default:
return state;
}
}
export default counterReducer;
然後我們在應用中創建 store:
1
2
3
4
5
6
7
// store.js
import { createStore } from 'redux';
import counterReducer from './counterReducer';
const store = createStore(counterReducer);
export default store;
4. 使用 Provider
將 Store 連接到 React 應用
在 React 應用中,我們需要使用 Provider
組件來將 Redux store 提供給整個應用,這樣所有子組件都可以訪問 store。
1
2
3
4
5
6
7
8
9
10
11
12
13
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import App from './App';
import store from './store';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
5. 在組件中使用 Redux
現在我們可以在 React 組件中使用 Redux 的狀態和 dispatch 功能。React-Redux 提供了 useSelector
和 useDispatch
這兩個 hooks 來幫助我們讀取和修改 Redux 狀態。
5.1 讀取 Redux 狀態:useSelector
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Counter.js
import React from 'react';
import { useSelector } from 'react-redux';
function Counter() {
const count = useSelector((state) => state.count);
return (
<div>
<h1>計數: {count}</h1>
</div>
);
}
export default Counter;
useSelector
可以讓你從 Redux store 中讀取狀態。
5.2 發送 Actions:useDispatch
要更新狀態,我們需要使用 useDispatch
來發送 actions。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Counter.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
function Counter() {
const count = useSelector((state) => state.count);
const dispatch = useDispatch();
return (
<div>
<h1>計數: {count}</h1>
<button onClick={() => dispatch({ type: 'INCREMENT' })}>增加</button>
<button onClick={() => dispatch({ type: 'DECREMENT' })}>減少</button>
</div>
);
}
export default Counter;
這裡我們通過 dispatch
發送 INCREMENT
和 DECREMENT
的 actions 來更新計數。
6. Action Creators
在大型應用中,直接在組件中寫 action 對象會導致代碼冗長。通常,我們會使用 Action Creators 來封裝 action 對象。
1
2
3
4
5
6
7
8
9
10
11
12
// actions.js
export const increment = () => {
return {
type: 'INCREMENT'
};
};
export const decrement = () => {
return {
type: 'DECREMENT'
};
};
然後在組件中使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Counter.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement } from './actions';
function Counter() {
const count = useSelector((state) => state.count);
const dispatch = useDispatch();
return (
<div>
<h1>計數: {count}</h1>
<button onClick={() => dispatch(increment())}>增加</button>
<button onClick={() => dispatch(decrement())}>減少</button>
</div>
);
}
export default Counter;
這樣,我們就將 actions 的定義從組件中抽離出來,讓代碼更加清晰。
7. 中間件與異步 Actions
Redux 自身只能處理同步的狀態變化,而現代應用中經常需要處理異步請求,比如從 API 獲取數據。這時,我們可以使用 Redux Thunk 這個中間件來幫助處理異步 actions。
7.1 安裝 Redux Thunk
1
npm install redux-thunk
7.2 配置 Redux Thunk
1
2
3
4
5
6
7
8
// store.js
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import counterReducer from './counterReducer';
const store = createStore(counterReducer, applyMiddleware(thunk));
export default store;
7.3 創建異步 Action
我們可以創建一個異步的 action 來從 API 獲取數據,並根據數據更新 Redux 狀態。
1
2
3
4
5
6
7
8
9
10
// actions.js
export const fetchData = () => {
return (dispatch) => {
fetch('https://api.example.com/data')
.then((response) => response.json())
.then((data) => {
dispatch({ type: 'SET_DATA', payload: data });
});
};
};
然後在 reducer 中處理該 action:
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
// counterReducer.js
const initialState = {
count: 0,
data: []
};
function counterReducer(state = initialState, action) {
switch (action.type) {
case 'INCREMENT':
return {
...state,
count: state.count + 1
};
case 'DECREMENT':
return {
...state,
count: state.count - 1
};
case 'SET_DATA':
return {
...state,
data: action.payload
};
default:
return state;
}
}
export default counterReducer;
8. Redux DevTools
在開發過程中,Redux 提供了 Redux DevTools,可以讓你監控應用狀態變化。使用 DevTools 你可以輕鬆地查看每一個 action 的觸發及其對狀態的影響。
8.1 配置 Redux DevTools
1
2
3
4
5
6
7
8
9
// store.js
import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import thunk from 'redux-thunk';
import counterReducer from './counterReducer';
const store = createStore(counterReducer, composeWithDevTools(applyMiddleware(thunk)));
export default store;
9. 總結
- Redux 提供了一個全局狀態管理的解決方案,適合大型應用中處理複雜的狀態邏輯。
- React-Redux 提供了
useSelector
和useDispatch
兩個 hooks 來讓 React 組件讀取和更新 Redux 狀態。 - 可以通過 Action Creators 來封裝 actions,使代碼更加清晰。
- Redux Thunk 可以幫助我們處理異步操作,將數據請求結果集成到 Redux 中。
- Redux DevTools 則讓我們更方便地
調試和監控應用中的狀態變化。
這樣,React 與 Redux 的結合能夠讓應用中的狀態管理變得更有結構性和可維護性。