useState
và useReducer
đều là các React Hooks cho phép quản lý state trong ứng dụng của bạn. useState
thường quản lý những state đơn lẻ trong khi useReducer
thì mạnh mẽ hơn trong việc quản lý các state phức tạp, nhiều logic xử lý, ngoài ra nó giúp tách biệt giữa UI và logic ra những phần riêng biệt để developer dễ theo dõi, maintain.
Function
src\App.jsx
Copy import { useState } from "react";
function App() {
const [count, setCount] = useState(0);
const handleDecrement = () => setCount(count - 1);
const handleIncrement = () => setCount(count + 1);
return (
<>
<p>Count: {count}</p>
<button onClick={handleDecrement}>Decrement</button>
<button onClick={handleIncrement}>Increment</button>
</>
);
}
export default App;
Class
src\App.jsx
Copy import Counter from "./ui/counter";
function App() {
return (
<>
<Counter />
</>
);
}
export default App;
src\consts\ActionType.jsx
Copy export default {
initialState: {
count: 0
},
INCREMENT: 'increment',
DECREMENT: 'decrement'
}
src\reducer\index.jsx
Copy import ActionType from "../consts/ActionType";
const myReducer = (state, action) => {
switch (action.type) {
case ActionType.INCREMENT:
return { count: state.count + 1 }
case ActionType.DECREMENT:
return { count: state.count - 1 }
default:
return state
}
}
export default myReducer;
src\ui\counter.jsx
Copy import { useReducer } from "react";
import myReducer from "../reducer";
import ActionType from "../consts/ActionType";
const Counter = () => {
const [state, dispatch] = useReducer(myReducer, ActionType.initialState)
const handleDecrement = () => dispatch({ type: ActionType.DECREMENT })
const handleIncrement = () => dispatch({ type: ActionType.INCREMENT })
return (
<>
<p>Count: {state.count}</p>
<button onClick={handleDecrement}>Decrement</button>
<button onClick={handleIncrement}>Increment</button>
</>
)
}
export default Counter;
1. useState cơ bản
Copy import React, { useState } from 'react'
const Counter = () => {
const [count, setCount] = useState(0)
const handleIncrement = () => setCount(count + 1)
return (
<>
<p>Count: {count}</p>
<button onClick={handleIncrement}>Increment</button>
</>
)
}
export default Counter
2. Sử dụng useReducer
Để chuyển từ useState
sang useReducer
bạn cần follow theo các bước sau:
(2-1) Xác định giá trị state ban đầu initialState
và các kiểu action action type
(2-2) Tạo một reducer function nhận vào state và action, tùy vào action mà xử lý trả về state tương ứng.
(2-3) Bên ngoài UI component ta thay thế useState
bằng useReducer
(2-3) useReducer
nhận vào reducer function ở trên và initialState
(2-3) useReducer
trả về state
và hàm dispatch
, hàm dispatch
để xác định sẽ thực hiện action gì
2-1. Khai báo initialState và action type
Copy const initialState = { count: 0 }
const INCREMENT = 'increment'
const DECREMENT = 'decrement'
2-2. Tạo reducer function
Copy const reducer = (state, action) => {
switch (action.type) {
case INCREMENT:
return { count: state.count + 1 }
case DECREMENT:
return { count: state.count - 1 }
default:
return state
}
}
2-3. Sử dụng ngoài UI component
Copy const Counter = () => {
const [state, dispatch] = useReducer(reducer, initialState)
const handleIncrement = () => dispatch({ type: INCREMENT })
return (
<>
<p>Count: {state.count}</p>
<button onClick={handleIncrement}>Increment</button>
</>
)
}
Ở bước 2-3
dispatch function gửi một action đến reducer function.
reducer function nhận action đó và kiểm tra.
Tùy thuộc vào action type sẽ xử lý và trả về state mới.
Khi state thay đổi thì ngoài UI component cũng sẽ tự động thay đổi theo.
2-4. Toàn bộ code
Để các bạn dễ theo dõi thì mình viết hết vào trong một file, thực tế thì nên tách riêng ra nhé
Copy import React, { useReducer } from 'react'
const initialState = { count: 0 }
const INCREMENT = 'increment'
const DECREMENT = 'decrement'
const reducer = (state, action) => {
switch (action.type) {
case INCREMENT:
return { count: state.count + 1 }
case DECREMENT:
return { count: state.count - 1 }
default:
return state
}
}
const Counter = () => {
const [state, dispatch] = useReducer(reducer, initialState)
const handleIncrement = () => dispatch({ type: INCREMENT })
const handleDecrement = () => dispatch({ type: DECREMENT })
return (
<>
<p>Count: {state.count}</p>
<button onClick={handleIncrement}>Increment</button>
<button onClick={handleDecrement}>Decrement</button>
</>
)
}
export default Counter
3. Kết luận
Trong ví dụ đơn giản trên, useReducer
không mang lại nhiều lợi ích hơn useState
(thậm chí còn rối rắm hơn). Nhưng nói chung, khi các thành phần của bạn trở nên phức tạp, useReducer
cung cấp một cách mạnh mẽ và linh hoạt để quản lý state, đặc biệt là khi bạn có những state phức tạp, nhiều logic xử lý, giúp tách biệt UI và logic rõ ràng.