Mục lục
Tại sao cần Global State? Vấn đề Prop Drilling
Khi xây dựng các ứng dụng React ngày càng lớn, bạn sẽ đối mặt với một thách thức phổ biến: quản lý trạng thái (state). Ban đầu, mọi thứ có thể đơn giản với state cục bộ (local state) trong từng component bằng cách sử dụng useState. Tuy nhiên, khi dữ liệu cần được chia sẻ giữa các component không có quan hệ cha-con trực tiếp, hoặc giữa nhiều cấp độ lồng nhau trong cây component, việc truyền state và các hàm cập nhật state thông qua props trở nên cồng kềnh. Đây chính là hiện tượng “prop drilling” – bạn phải khoan (drill) props xuống nhiều tầng component trung gian chỉ để dữ liệu đến được nơi cần nó, ngay cả khi các component trung gian đó không cần dùng đến dữ liệu đó.
Điều này không chỉ làm cho code của bạn khó đọc và bảo trì hơn, mà còn tăng nguy cơ xảy ra lỗi khi bạn cần thay đổi cấu trúc component hoặc thêm/bớt các props. Thay vì phải truyền dữ liệu “thẳng” từ component này sang component khác, chúng ta cần một cơ chế để dữ liệu có thể được “phát sóng” đến bất kỳ component nào trong cây cần nó, mà không cần đi qua các tầng trung gian không liên quan.
Đây là lúc khái niệm “Global State” (Trạng thái Toàn cục) xuất hiện. Global state là trạng thái có thể được truy cập và cập nhật từ bất kỳ component nào trong ứng dụng, bất kể vị trí của nó trong cây component. Trong nhiều năm, các thư viện quản lý state bên ngoài như Redux đã trở thành giải pháp phổ biến cho vấn đề này. Tuy nhiên, React hiện đại đã cung cấp một công cụ tích hợp mạnh mẽ, đủ cho nhiều trường hợp sử dụng mà không cần đến thư viện bên ngoài: Context API và hook `useContext`.
Context API là gì?
Context API là một tính năng của React cho phép bạn chia sẻ dữ liệu qua cây component mà không cần truyền props xuống theo cách thủ công ở mọi cấp độ. Nó được thiết kế để truyền các loại dữ liệu “global” cho một cây con của React, ví dụ như cài đặt ngôn ngữ, thông tin người dùng đã đăng nhập, hoặc chủ đề giao diện (theme) hiện tại.
Trước khi hook `useContext` ra đời, việc tiêu thụ Context có thể hơi phức tạp hơn một chút, thường sử dụng `Context.Consumer` hoặc `contextType` trong class components (bạn có thể đọc lại về sự khác biệt giữa Class và Functional Components để hiểu rõ hơn). Nhưng với sự ra đời của React Hooks, đặc biệt là `useContext`, việc làm việc với Context đã trở nên trực quan và dễ dàng hơn rất nhiều trong các functional components.
Về cơ bản, Context API cung cấp hai thứ chính:
- Context Object: Được tạo ra bằng `React.createContext()`. Đây là “kênh” mà dữ liệu sẽ đi qua.
- Context.Provider: Là một component được sử dụng để “cung cấp” (provide) giá trị cho Context. Tất cả các component con nằm bên trong `Context.Provider` (bất kể cấp độ lồng nhau) đều có thể truy cập giá trị này.
- Context.Consumer: (ít dùng hơn trong functional components hiện đại) Hoặc hook `useContext` (được sử dụng trong functional components) để “tiêu thụ” (consume) giá trị từ Context đã được cung cấp.
Trong bài viết này, chúng ta sẽ tập trung vào cách sử dụng hook `useContext` để tiêu thụ Context, kết hợp với `Context.Provider` để cung cấp dữ liệu, nhằm xây dựng một giải pháp quản lý global state đơn giản nhưng hiệu quả.
useContext hoạt động như thế nào?
`useContext` là một React Hook cho phép bạn đọc giá trị của một Context và đăng ký lắng nghe các thay đổi của nó. Khi giá trị Context mà `useContext` đang theo dõi thay đổi, component sử dụng hook này sẽ tự động re-render (kết xuất lại).
Cú pháp rất đơn giản:
const value = useContext(MyContext);
Ở đây, `MyContext` là Context object mà bạn đã tạo ra bằng `React.createContext()`. Hook này sẽ trả về giá trị hiện tại của Context đó. Giá trị này chính là giá trị được truyền vào prop `value` của `
Nếu không có `
Việc kết hợp `Context.Provider` và `useContext` cho phép chúng ta tách biệt nơi dữ liệu được cung cấp (thường ở gần gốc của cây component hoặc ở một node chung cao hơn) và nơi dữ liệu được sử dụng (ở bất kỳ component con nào cần nó), loại bỏ nhu cầu truyền props qua các tầng trung gian.
Hướng dẫn Chi tiết Cách Sử dụng useContext cho Global State
Để sử dụng `useContext` cho global state, bạn cần thực hiện các bước sau:
Bước 1: Tạo Context
Đầu tiên, bạn cần tạo một Context object bằng cách gọi `React.createContext()`. Thông thường, bạn sẽ làm điều này trong một file riêng biệt để dễ quản lý.
// context/ThemeContext.js
import React from 'react';
// Tạo Context object. Có thể truyền giá trị mặc định ở đây.
// Giá trị mặc định này chỉ được sử dụng khi không có Provider nào.
const ThemeContext = React.createContext('light');
export default ThemeContext;
Ở đây, chúng ta tạo một `ThemeContext` với giá trị mặc định là ‘light’.
Bước 2: Cung cấp Context (Context.Provider)
Tiếp theo, bạn cần một component (hoặc đặt trực tiếp trong App component của bạn) sử dụng `Context.Provider` để bọc các component con cần truy cập Context này. Prop `value` của Provider là nơi bạn đặt dữ liệu global state mà bạn muốn chia sẻ.
// context/ThemeProvider.js
import React, { useState } from 'react';
import ThemeContext from './ThemeContext';
const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState('light'); // State thực tế
// Giá trị cung cấp qua Context
// Bao gồm state và hàm cập nhật state
const contextValue = {
theme: theme,
toggleTheme: () => {
setTheme(prevTheme => (prevTheme === 'light' ? 'dark' : 'light'));
}
};
return (
<ThemeContext.Provider value={contextValue}>
{children}
</ThemeContext.Provider>
);
};
export default ThemeProvider;
Trong ví dụ này, chúng ta tạo một component `ThemeProvider` quản lý state `theme` bằng `useState`. Nó sau đó truyền object chứa `theme` và hàm `toggleTheme` vào prop `value` của `ThemeContext.Provider`. Prop `children` đảm bảo rằng tất cả các component con được truyền vào `ThemeProvider` sẽ có thể truy cập Context này.
Bạn sẽ bọc ứng dụng của mình hoặc phần ứng dụng cần Context bằng `ThemeProvider` này, thường là ở file `App.js` hoặc `index.js`:
// App.js
import React from 'react';
import ThemeProvider from './context/ThemeProvider';
import MyPage from './components/MyPage'; // Component con bất kỳ
function App() {
return (
<ThemeProvider>
<div className="App">
<h1>Ứng dụng của tôi</h1>
<MyPage /> {/* MyPage và mọi thứ bên trong nó đều có thể dùng ThemeContext */}
</div>
</ThemeProvider>
);
}
export default App;
Bước 3: Tiêu thụ Context (useContext Hook)
Cuối cùng, trong bất kỳ functional component con nào nằm bên trong `
// components/ThemeButton.js
import React, { useContext } from 'react';
import ThemeContext from '../context/ThemeContext';
const ThemeButton = () => {
// Sử dụng hook useContext để lấy giá trị từ ThemeContext
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<button onClick={toggleTheme}>
Chuyển sang chế độ {theme === 'light' ? 'Tối' : 'Sáng'}
</button>
);
};
export default ThemeButton;
Component `ThemeButton` này không nhận bất kỳ props nào liên quan đến theme. Nó truy cập `theme` và `toggleTheme` trực tiếp từ `ThemeContext` bằng hook `useContext`. Bằng cách này, chúng ta đã loại bỏ được prop drilling cho dữ liệu theme.
Ví dụ Thực tế: Xây dựng một Theme Switcher đơn giản
Hãy ghép nối các phần trên lại để tạo một ví dụ hoàn chỉnh về Theme Switcher.
// src/contexts/ThemeContext.js
import { createContext } from 'react';
const ThemeContext = createContext({
theme: 'light', // Giá trị mặc định
toggleTheme: () => {}, // Hàm rỗng mặc định
});
export default ThemeContext;
// src/contexts/ThemeProvider.js
import React, { useState } from 'react';
import ThemeContext from './ThemeContext';
const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme(prevTheme => (prevTheme === 'light' ? 'dark' : 'light'));
};
// Cung cấp state và hàm cập nhật qua Context
const contextValue = {
theme: theme,
toggleTheme: toggleTheme,
};
return (
<ThemeContext.Provider value={contextValue}>
{children}
</ThemeContext.Provider>
);
};
export default ThemeProvider;
// src/components/ThemeButton.js
import React, { useContext } from 'react';
import ThemeContext from '../contexts/ThemeContext';
const ThemeButton = () => {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<button onClick={toggleTheme} style={{
backgroundColor: theme === 'light' ? '#fff' : '#333',
color: theme === 'light' ? '#333' : '#fff',
padding: '10px',
border: '1px solid ' + (theme === 'light' ? '#ccc' : '#666'),
cursor: 'pointer'
}}>
Chuyển sang chế độ {theme === 'light' ? 'Tối' : 'Sáng'}
</button>
);
};
export default ThemeButton;
// src/components/ThemedDiv.js
import React, { useContext } from 'react';
import ThemeContext from '../contexts/ThemeContext';
const ThemedDiv = ({ children }) => {
const { theme } = useContext(ThemeContext);
return (
<div style={{
backgroundColor: theme === 'light' ? '#f0f0f0' : '#222',
color: theme === 'light' ? '#333' : '#fff',
padding: '20px',
marginTop: '20px',
border: '1px solid ' + (theme === 'light' ? '#ccc' : '#666')
}}>
{children}
</div>
);
};
export default ThemedDiv;
// src/App.js
import React from 'react';
import ThemeProvider from './contexts/ThemeProvider';
import ThemeButton from './components/ThemeButton';
import ThemedDiv from './components/ThemedDiv';
import './App.css'; // CSS đơn giản nếu cần
function App() {
return (
<ThemeProvider>
<div className="App">
<h1>Ứng dụng Theme Switcher</h1>
<ThemeButton />
<ThemedDiv>
<p>Đây là nội dung được ảnh hưởng bởi Theme.</p>
<p>Component này không nhận props theme, nó đọc từ Context.</p>
</ThemedDiv>
{/* Các component khác cũng có thể dùng useContext(ThemeContext) */}
</div>
</ThemeProvider>
);
}
export default App;
Trong ví dụ này, `App` component bọc toàn bộ nội dung bằng `ThemeProvider`. `ThemeButton` và `ThemedDiv` (hoặc bất kỳ component nào khác bên trong) có thể truy cập `theme` và `toggleTheme` trực tiếp bằng `useContext(ThemeContext)` mà không cần prop drilling. Đây là một cách hiệu quả để quản lý global state đơn giản.
Kết hợp useContext với useReducer cho State Phức tạp
Đối với state phức tạp hơn, nơi các cập nhật liên quan đến logic nhiều bước hoặc phụ thuộc vào state trước đó (như giỏ hàng, quản lý form phức tạp), việc kết hợp `useContext` với hook useReducer là một mẫu thiết kế rất mạnh mẽ. `useReducer` giúp quản lý logic cập nhật state một cách rõ ràng thông qua các “actions” và “reducer function”, trong khi `useContext` giúp phân phối state hiện tại và hàm `dispatch` (để gửi actions) xuống cây component.
Cách làm là bạn sẽ sử dụng `useReducer` trong component Provider của mình để quản lý state và nhận hàm `dispatch`. Sau đó, bạn truyền cả state (hoặc phần state cần thiết) và hàm `dispatch` vào prop `value` của `Context.Provider`. Các component tiêu thụ sẽ dùng `useContext` để lấy về state và `dispatch`, sau đó gọi `dispatch` với các action object khi cần thay đổi state.
Ví dụ cấu trúc:
// contexts/CounterContext.js
import { createContext } from 'react';
const CounterContext = createContext(); // Không cần giá trị mặc định phức tạp ở đây
export default CounterContext;
// contexts/CounterProvider.js
import React, { useReducer } from 'react';
import CounterContext from './CounterContext';
// Reducer function
const counterReducer = (state, action) => {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
case 'DECREMENT':
return { count: state.count - 1 };
case 'RESET':
return { count: 0 };
default:
return state;
}
};
const CounterProvider = ({ children }) => {
const [state, dispatch] = useReducer(counterReducer, { count: 0 }); // Initial state
// Cung cấp state và dispatch
const contextValue = { state, dispatch };
return (
<CounterContext.Provider value={contextValue}>
{children}
</CounterContext.Provider>
);
};
export default CounterProvider;
// components/CounterDisplay.js
import React, { useContext } from 'react';
import CounterContext from '../contexts/CounterContext';
const CounterDisplay = () => {
const { state } = useContext(CounterContext);
return <h2>Count: {state.count}</h2>;
};
export default CounterDisplay;
// components/CounterControls.js
import React, { useContext } from 'react';
import CounterContext from '../contexts/CounterContext';
const CounterControls = () => {
const { dispatch } = useContext(CounterContext);
return (
<div>
<button onClick={() => dispatch({ type: 'INCREMENT' })}>Tăng</button>
<button onClick={() => dispatch({ type: 'DECREMENT' })}>Giảm</button>
<button onClick={() => dispatch({ type: 'RESET' })}>Reset</button>
</div>
);
};
export default CounterControls;
// App.js
import React from 'react';
import CounterProvider from './contexts/CounterProvider';
import CounterDisplay from './components/CounterDisplay';
import CounterControls from './components/CounterControls';
function App() {
return (
<CounterProvider>
<div className="App">
<h1>Ứng dụng Counter với useContext & useReducer</h1>
<CounterDisplay />
<CounterControls />
</div>
</CounterProvider>
);
}
export default App;
Mẫu này rất linh hoạt. `useReducer` giúp tập trung logic cập nhật state, làm cho Provider trở nên gọn gàng và dễ kiểm thử, trong khi `useContext` giúp phân phối state và `dispatch` đến mọi nơi cần thiết mà không cần truyền props.
Khi nào nên dùng useContext cho Global State?
`useContext` là một giải pháp tuyệt vời cho global state trong các trường hợp sau:
- Ứng dụng nhỏ và trung bình: Đối với các ứng dụng không quá phức tạp, chỉ có một vài loại global state (như theme, user info, ngôn ngữ), `useContext` cung cấp đủ chức năng mà không cần thêm dependency bên ngoài.
- Dữ liệu ít thay đổi hoặc thay đổi không quá thường xuyên: Theme, thông tin người dùng đã đăng nhập, cài đặt cấu hình ứng dụng là những ví dụ điển hình.
- Thay thế prop drilling: Đây là mục đích ban đầu của Context API. Bất cứ khi nào bạn thấy mình truyền cùng một prop qua nhiều tầng component, hãy nghĩ đến Context.
- Khi kết hợp với `useReducer`: Đối với state phức tạp hơn một chút nhưng bạn vẫn muốn giữ mọi thứ trong phạm vi React Hooks và không muốn dùng thư viện ngoài.
Những Hạn chế và Cần Lưu ý khi dùng useContext
Mặc dù mạnh mẽ, `useContext` không phải là viên đạn bạc cho mọi bài toán quản lý state và có những hạn chế cần lưu ý:
- Vấn đề hiệu năng (Performance): Đây là hạn chế lớn nhất. Khi giá trị được truyền vào `Context.Provider` thay đổi, *tất cả* các component con (và con của chúng) sử dụng `useContext` để đọc Context đó sẽ bị re-render, ngay cả khi chúng chỉ sử dụng một phần của giá trị đó hoặc phần giá trị chúng sử dụng không thay đổi. Điều này có thể gây ra các re-render không cần thiết và ảnh hưởng đến hiệu năng trong các ứng dụng lớn với state thay đổi thường xuyên.
- Khó gỡ lỗi (Debugging): So với các thư viện như Redux có Redux DevTools mạnh mẽ để theo dõi mọi action và state change, việc gỡ lỗi các luồng cập nhật state với `useContext` có thể khó khăn hơn, đặc biệt khi state trở nên phức tạp.
- Tổ chức code: Với số lượng Context lớn, việc quản lý và tổ chức các file Context và Provider có thể trở nên lộn xộn nếu không có cấu trúc rõ ràng.
Để giảm thiểu vấn đề hiệu năng, bạn có thể áp dụng một số chiến lược:
- Chia nhỏ Context: Thay vì một Context lớn chứa tất cả global state, hãy tạo nhiều Context nhỏ hơn cho từng phần dữ liệu độc lập (ví dụ: `AuthContext`, `ThemeContext`, `SettingsContext`). Các component chỉ tiêu thụ Context mà chúng thực sự cần.
- Sử dụng `useMemo` cho giá trị Context: Nếu giá trị Context là một object hoặc array được tạo mới trên mỗi lần render của Provider (như trong ví dụ ThemeProvider của chúng ta), bạn nên bọc nó bằng `useMemo` để đảm bảo object chỉ được tạo lại khi các dependency thực sự thay đổi.
const contextValue = useMemo(() => ({ theme: theme, toggleTheme: toggleTheme, }), [theme]); // Dependency là theme
Lưu ý: Cần cẩn thận với việc lạm dụng `useMemo`, nó cũng có chi phí. Hãy profle ứng dụng của bạn để xem liệu việc tối ưu này có cần thiết không.
- Sử dụng các selector: Mặc dù không tích hợp sẵn như trong Redux, bạn có thể tạo custom hook hoặc helper function để chỉ trích xuất phần state cụ thể từ Context, và kết hợp với `React.memo` cho component tiêu thụ để tránh re-render khi phần state component đó cần không thay đổi.
useContext vs. Redux (và các thư viện khác)
Vậy, khi nào bạn nên dùng `useContext` và khi nào nên dùng Redux hoặc các thư viện quản lý state khác như Zustand, Recoil, MobX? Đây là bảng so sánh nhanh:
Đặc điểm | useContext | Redux | Các thư viện khác (Zustand, Recoil, MobX…) |
---|---|---|---|
Tính năng | Built-in trong React, API đơn giản (Provider, useContext). Chỉ cung cấp cơ chế truyền dữ liệu. | Thư viện ngoài. Cung cấp kho lưu trữ tập trung, luồng dữ liệu chặt chẽ (actions, reducers), middleware, devtools. | Thư viện ngoài, với các triết lý khác nhau (minimalist, atomic state, reactive). Thường cung cấp giải pháp tối ưu hơn Redux về boilerplate hoặc hiệu năng. |
Độ phức tạp cài đặt ban đầu | Rất thấp. Chỉ cần tạo Context và Provider. | Cao hơn. Cần cài thư viện, setup store, reducers, actions. | Thay đổi tùy thư viện, thường đơn giản hơn Redux nhưng phức tạp hơn useContext đơn thuần. |
Boilerplate (Mã mẫu) | Ít cho state đơn giản. Có thể tăng khi kết hợp useReducer cho state phức tạp. | Nhiều hơn (actions, action creators, reducers, constants). Redux Toolkit giảm đáng kể boilerplate. | Thay đổi tùy thư viện, thường ít hơn Redux truyền thống. |
Hiệu năng (với state thay đổi thường xuyên) | Có thể gặp vấn đề re-render không cần thiết nếu không tối ưu (chia Context, useMemo). | Tốt. Sử dụng selectors và tối ưu re-render hiệu quả. | Thường rất tốt, nhiều thư viện thiết kế với hiệu năng là ưu tiên hàng đầu. |
Gỡ lỗi (Debugging) | Khó hơn với state phức tạp. Cần dùng React DevTools hoặc console.log. | Rất tốt với Redux DevTools (history, time-travel debugging). | Thay đổi tùy thư viện. Một số có devtools riêng hoặc tích hợp tốt với React DevTools. |
Best Use Case | Global state đơn giản (theme, user info), thay thế prop drilling trong ứng dụng nhỏ/trung bình. | Ứng dụng lớn, phức tạp với nhiều nguồn dữ liệu, state thay đổi thường xuyên, logic cập nhật phức tạp, cần các tính năng nâng cao (middleware, logging). | Ứng dụng trung bình/lớn, khi bạn tìm kiếm giải pháp tối ưu hơn Redux về boilerplate hoặc hiệu năng nhưng vẫn cần quản lý state tập trung. |
`useContext` là lựa chọn mặc định tốt khi bắt đầu với global state trong React vì sự đơn giản và tích hợp sẵn. Bạn chỉ nên cân nhắc chuyển sang Redux hoặc thư viện khác khi ứng dụng của bạn thực sự phát triển lớn và phức tạp, các hạn chế về hiệu năng và gỡ lỗi của `useContext` trở thành vấn đề lớn, và bạn cần các tính năng mạnh mẽ hơn mà các thư viện đó cung cấp.
Các Thực hành Tốt nhất khi dùng useContext
- Tạo Context và Provider riêng biệt: Giữ logic Context (tạo Context, Provider component) tách biệt trong các file/folder riêng giúp code sạch sẽ và dễ tái sử dụng hơn.
- Đặt Provider ở vị trí thích hợp: Đặt `Provider` ở nơi cao nhất trong cây component sao cho tất cả các component cần truy cập Context đều nằm bên trong nó. Thường là ở gốc ứng dụng hoặc một phần lớn của ứng dụng.
- Chỉ cung cấp những gì cần thiết: Đừng cung cấp toàn bộ state của ứng dụng vào một Context duy nhất. Hãy chia nhỏ state thành các Context liên quan theo từng tính năng hoặc loại dữ liệu.
- Kết hợp với useReducer cho state phức tạp: Như đã thảo luận, mẫu `useContext + useReducer` là rất hiệu quả cho state có logic cập nhật phức tạp.
- Cân nhắc tối ưu hiệu năng khi cần: Sử dụng `useMemo` cho giá trị Provider và `React.memo` cho các component tiêu thụ nếu gặp vấn đề về hiệu năng do re-render không cần thiết.
- Tạo Custom Hook để tiêu thụ Context: Thay vì gọi `useContext(MyContext)` trực tiếp trong mọi component, bạn có thể tạo một custom hook đơn giản như `useMyFeature`:
import { useContext } from 'react'; import MyContext from './MyContext'; const useMyFeature = () => { const context = useContext(MyContext); if (context === undefined) { throw new Error('useMyFeature must be used within a MyFeatureProvider'); } return context; }; export default useMyFeature;
Hook này giúp code sạch hơn, cung cấp một lớp trừu tượng và cho phép thêm logic kiểm tra (ví dụ: đảm bảo hook được gọi bên trong Provider). Bạn có thể đọc thêm về việc tạo Custom Hooks.
Kết luận
`useContext` là một công cụ mạnh mẽ và là một phần không thể thiếu của React hiện đại. Nó cung cấp một giải pháp tích hợp sẵn để quản lý global state và giải quyết vấn đề prop drilling một cách hiệu quả cho nhiều trường hợp sử dụng, đặc biệt là trong các ứng dụng nhỏ và trung bình hoặc cho các loại state ít thay đổi.
Hiểu và sử dụng thành thạo `useContext`, đặc biệt khi kết hợp với useReducer, sẽ giúp bạn xây dựng các ứng dụng React sạch sẽ, dễ bảo trì và mở rộng hơn mà không nhất thiết phải phụ thuộc vào các thư viện quản lý state bên ngoài ngay từ đầu. Hãy luôn cân nhắc sự phức tạp và nhu cầu của ứng dụng để đưa ra lựa chọn phù hợp nhất giữa `useContext` và các giải pháp khác.
Chúc mừng bạn đã thêm một công cụ quan trọng vào bộ kỹ năng React của mình! Hãy tiếp tục khám phá các chủ đề khác trong “Lộ trình React” để trở thành một lập trình viên React thành thạo.
Các Bài viết Liên quan trong Lộ trình React
- React Roadmap – Lộ trình học React 2025
- React Là Gì? Vì Sao Nó Chiếm Lĩnh Thế Giới Frontend
- Class vs Functional Components: Bước Chuyển Lớn Trong Thế Giới React Hiện Đại
- Hiểu về JSX: Khi JavaScript Gặp Gỡ Markup
- React Props vs State: Ai Kiểm Soát Dữ Liệu Gì? (React Roadmap)
- Làm Chủ Conditional Rendering trong React (React Roadmap)
- Kết hợp Component trong React: Tái sử dụng thật dễ dàng (React Roadmap)
- Vòng Đời Component trong React: Từ Khởi Tạo Đến Kết Thúc (React Roadmap)
- Làm việc với Danh sách và Key trong React (React Roadmap)
- Xử Lý Sự Kiện trong React: Cách Tiếp Cận ‘React Way’ (React Roadmap)
- Refs trong React là gì? Truy cập DOM Trực Tiếp Đúng Cách (React Roadmap)
- React Roadmap: Render Props vs Higher Order Components: Các Mẫu Thiết Kế Trong Thực Tế
- useState và useEffect: Siêu Năng Lực Nhập Môn của React (React Roadmap)
- Tạo Custom Hooks trong React: Biến Tái Sử Dụng Mã Thành Nghệ Thuật (React Roadmap)
- Khi nào và Vì sao nên dùng useCallback, useMemo, và useRef (React Roadmap)
- Quản lý State với useReducer: Gọn gàng và Dễ đoán (React Roadmap)