Hướng dẫn React Hooks từ cơ bản đến nâng cao
React Hooks đã thay đổi cách chúng ta viết React components. Trong bài viết này, chúng ta sẽ tìm hiểu từ những khái niệm cơ bản đến các kỹ thuật nâng cao.
React Hooks là gì?
React Hooks là các function đặc biệt cho phép bạn "hook into" các tính năng của React từ functional components. Hooks được giới thiệu trong React 16.8.
Tại sao sử dụng Hooks?
- Đơn giản hóa code: Không cần class components
- Tái sử dụng logic: Dễ dàng chia sẻ logic giữa components
- Dễ test: Functional components dễ test hơn
- Performance tốt hơn: Ít overhead hơn class components
Các Hook cơ bản
useState Hook
Quản lý state trong functional components:
function Counter() {
const [count, setCount] = useState(0);
const [name, setName] = useState('');
return (
<div>
<p>Bạn đã click {count} lần</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
<input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Nhập tên của bạn"
/>
</div>
);
}
useEffect Hook
Xử lý side effects trong components:
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
// Effect chạy sau mỗi render
useEffect(() => {
fetchUser(userId)
.then(userData => {
setUser(userData);
setLoading(false);
});
}, [userId]); // Dependency array
// Effect cleanup
useEffect(() => {
const timer = setInterval(() => {
console.log('Timer tick');
}, 1000);
return () => {
clearInterval(timer); // Cleanup
};
}, []);
if (loading) return <div>Đang tải...</div>;
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
}
useContext Hook
Sử dụng React Context dễ dàng hơn:
// Tạo Context
const ThemeContext = createContext();
// Provider component
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
);
}
// Component sử dụng Context
function ThemedButton() {
const { theme, setTheme } = useContext(ThemeContext);
return (
<button
style={{
backgroundColor: theme === 'light' ? '#fff' : '#333',
color: theme === 'light' ? '#333' : '#fff'
}}
onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}
>
Chuyển đổi theme ({theme})
</button>
);
}
Các Hook nâng cao
useReducer Hook
Quản lý state phức tạp với reducer pattern:
// Reducer function
function todoReducer(state, action) {
switch (action.type) {
case 'ADD_TODO':
return [...state, {
id: Date.now(),
text: action.text,
completed: false
}];
case 'TOGGLE_TODO':
return state.map(todo =>
todo.id === action.id
? { ...todo, completed: !todo.completed }
: todo
);
case 'DELETE_TODO':
return state.filter(todo => todo.id !== action.id);
default:
return state;
}
}
function TodoApp() {
const [todos, dispatch] = useReducer(todoReducer, []);
const [inputText, setInputText] = useState('');
const addTodo = () => {
if (inputText.trim()) {
dispatch({ type: 'ADD_TODO', text: inputText });
setInputText('');
}
};
return (
<div>
<input
value={inputText}
onChange={(e) => setInputText(e.target.value)}
placeholder="Thêm công việc mới"
/>
<button onClick={addTodo}>Thêm</button>
<ul>
{todos.map(todo => (
<li key={todo.id}>
<span
style={{
textDecoration: todo.completed ? 'line-through' : 'none'
}}
onClick={() => dispatch({ type: 'TOGGLE_TODO', id: todo.id })}
>
{todo.text}
</span>
<button
onClick={() => dispatch({ type: 'DELETE_TODO', id: todo.id })}
>
Xóa
</button>
</li>
))}
</ul>
</div>
);
}
Custom Hooks
Tạo custom hooks để tái sử dụng logic:
// Custom hook cho API calls
function useApi(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
setLoading(true);
const response = await fetch(url);
const result = await response.json();
setData(result);
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error };
}
// Custom hook cho local storage
function useLocalStorage(key, initialValue) {
const [storedValue, setStoredValue] = useState(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
return initialValue;
}
});
const setValue = (value) => {
try {
setStoredValue(value);
window.localStorage.setItem(key, JSON.stringify(value));
} catch (error) {
console.error(error);
}
};
return [storedValue, setValue];
}
Best Practices
Rules of Hooks
- Chỉ gọi Hooks ở top level - Không gọi trong loops, conditions, hoặc nested functions
- Chỉ gọi Hooks từ React functions - Components hoặc custom Hooks
Performance Tips
// ✅ Good: Dependency array chính xác
useEffect(() => {
fetchData(userId);
}, [userId]);
// ❌ Bad: Missing dependency
useEffect(() => {
fetchData(userId);
}, []); // userId should be in dependency array
// ✅ Good: Sử dụng useCallback cho event handlers
const handleClick = useCallback(() => {
doSomething(value);
}, [value]);
// ✅ Good: Sử dụng useMemo cho expensive calculations
const expensiveValue = useMemo(() => {
return heavyCalculation(data);
}, [data]);
Kết luận
React Hooks đã làm cho việc viết React components trở nên đơn giản và mạnh mẽ hơn. Với việc hiểu rõ các hooks cơ bản và nâng cao, bạn có thể:
- Viết code React sạch và dễ maintain
- Tái sử dụng logic hiệu quả với custom hooks
- Tối ưu hóa performance với useMemo và useCallback
- Quản lý state phức tạp với useReducer
Hãy thực hành thường xuyên và áp dụng các best practices để trở thành React developer giỏi hơn!
Chúc bạn coding vui vẻ! 🚀