← Về danh sách bài họcBài 7/25
🌐 Bài 7: useContext - Chia Sẻ Dữ Liệu Toàn Cục
🎯 Sau bài học này, bạn sẽ:
- Hiểu Context API và vấn đề prop drilling
- Tạo Context, Provider, và sử dụng useContext
- Xây dựng Theme Context và Auth Context thực tế
- Biết khi nào nên và không nên dùng Context
1. Vấn Đề Prop Drilling
Prop drilling xảy ra khi bạn phải truyền props qua nhiều tầng component chỉ để đến component con sâu bên trong.
// ❌ Prop drilling: theme phải truyền qua 3 tầng
function App() {
const [theme, setTheme] = useState('dark');
return <Layout theme={theme} />;
}
function Layout({ theme }) {
return <Sidebar theme={theme} />;
}
function Sidebar({ theme }) {
return <button className={theme}>Menu</button>;
}
// ✅ Context: component nào cũng truy cập được trực tiếp!
2. Tạo và Sử Dụng Context
import { createContext, useContext, useState } from 'react';
// Bước 1: Tạo Context
const ThemeContext = createContext('light');
// Bước 2: Tạo Provider component
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme(prev => prev === 'light' ? 'dark' : 'light');
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
// Bước 3: Sử dụng useContext
function Header() {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<header className={theme}>
<h1>My App</h1>
<button onClick={toggleTheme}>
{theme === 'light' ? '🌙' : '☀️'}
</button>
</header>
);
}
// Bước 4: Wrap App với Provider
function App() {
return (
<ThemeProvider>
<Header />
<MainContent />
</ThemeProvider>
);
}
3. Auth Context Thực Tế
const AuthContext = createContext(null);
// Custom hook để dùng auth (clean hơn)
function useAuth() {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuth phải dùng trong AuthProvider');
}
return context;
}
function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const login = async (email, password) => {
const res = await fetch('/api/login', {
method: 'POST',
body: JSON.stringify({ email, password })
});
const data = await res.json();
setUser(data.user);
};
const logout = () => setUser(null);
return (
<AuthContext.Provider value={{ user, login, logout }}>
{children}
</AuthContext.Provider>
);
}
// Sử dụng
function Navbar() {
const { user, logout } = useAuth();
return user
? <button onClick={logout}>Đăng xuất ({user.name})</button>
: <a href="/login">Đăng nhập</a>;
}
💡 Best Practice: Tạo custom hook (
useAuth, useTheme) wrap useContext + validation. Giúp code gọn hơn và báo lỗi rõ ràng khi dùng sai.
📝 Tóm Tắt
- Context giải quyết prop drilling
- 3 bước:
createContext→Provider→useContext - Tạo custom hook wrap useContext cho code sạch
- Dùng cho: theme, auth, locale, config toàn app
- Không dùng cho: local state, data thay đổi quá thường xuyên