Trước Hooks, để có state trong component bạn phải dùng class component với this.setState — cú pháp verbose và dễ gây bug. Hooks ra đời năm 2019 và nhanh chóng trở thành cách duy nhất đáng học để viết React.
useState — State Cơ Bản
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
Đếm: {count}
);
}
// State với object
function Form() {
const [form, setForm] = useState({ name: '', email: '' });
const handleChange = (e) => {
setForm(prev => ({ ...prev, [e.target.name]: e.target.value }));
};
}
Quan trọng: Luôn dùng functional update (prev =>) khi state mới phụ thuộc state cũ — tránh stale closure bugs.
useEffect — Side Effects
import { useEffect, useState } from 'react';
function PostDetail({ postId }) {
const [post, setPost] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
let cancelled = false;
fetch(`/api/posts/${postId}`)
.then(r => r.json())
.then(data => {
if (!cancelled) {
setPost(data);
setLoading(false);
}
});
// Cleanup — tránh race condition
return () => { cancelled = true; };
}, [postId]); // Chạy lại khi postId thay đổi
if (loading) return Đang tải...
;
return {post.title}
;
}
useContext — Tránh Prop Drilling
import { createContext, useContext, useState } from 'react';
const ThemeContext = createContext('light');
function App() {
const [theme, setTheme] = useState('light');
return (
);
}
// Dùng ở bất kỳ component con nào
function Header() {
const { theme, setTheme } = useContext(ThemeContext);
return (
);
}
useRef — Truy Cập DOM Và Giá Trị Bền Vững
function SearchInput() {
const inputRef = useRef(null);
// Focus input khi mount
useEffect(() => {
inputRef.current?.focus();
}, []);
return ;
}
// useRef lưu giá trị không trigger re-render
function Timer() {
const intervalRef = useRef(null);
const start = () => {
intervalRef.current = setInterval(() => {
console.log('tick');
}, 1000);
};
const stop = () => clearInterval(intervalRef.current);
}
useMemo Và useCallback — Tối Ưu Performance
// useMemo — cache kết quả tính toán nặng
const expensiveValue = useMemo(() => {
return heavyCalculation(data);
}, [data]); // Chỉ tính lại khi data thay đổi
// useCallback — cache hàm để tránh child re-render
const handleSubmit = useCallback((values) => {
api.submit(values);
}, []); // Hàm này không bao giờ thay đổi
Custom Hooks — Tái Sử Dụng Logic
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch(url)
.then(r => r.json())
.then(setData)
.catch(setError)
.finally(() => setLoading(false));
}, [url]);
return { data, loading, error };
}
// Dùng ở bất kỳ đâu
function PostList() {
const { data: posts, loading } = useFetch('/api/posts');
if (loading) return Loading...
;
return posts.map(p => {p.title});
}
Dependency array của useEffect là nguồn gốc của 90% bugs với hooks. Nếu bạn bỏ sót dependency, component sẽ dùng giá trị cũ. Luôn dùng eslint-plugin-react-hooks để cảnh báo.
Kết Luận
Nắm vững 4 hook cơ bản (useState, useEffect, useContext, useRef) là đủ cho phần lớn use case. useMemo và useCallback chỉ nên dùng khi đã xác định được performance bottleneck — đừng premature optimize.
Chưa có bình luận. Hãy là người đầu tiên!