Phase 1: Nền Tảng React — Components, Props, State & Hooks

Chào mừng đến với Phase 1 của series React & Next.js! Bài viết này dạy bạn các thành phần cốt lõi của React — những khái niệm bạn sẽ sử dụng trong mọi ứng dụng React từ nay về sau.
Chúng ta sẽ thực hành ngay lập tức. Đến cuối bài, bạn sẽ hiểu tại sao React ra đời, cách tư duy theo component, và cách quản lý state và side effects với hooks.
Thời gian cam kết: 5–7 ngày, 1–2 giờ mỗi ngày Điều kiện tiên quyết: JavaScript cơ bản (variables, functions, arrays, objects, promises)
Những Gì Bạn Sẽ Học
Sau khi hoàn thành Phase 1, bạn có thể:
✅ Giải thích React là gì và tại sao nó được tạo ra
✅ Viết JSX và hiểu cách nó ánh xạ sang JavaScript
✅ Xây dựng các components có thể tái sử dụng và kết hợp chúng
✅ Truyền dữ liệu giữa components bằng props
✅ Quản lý local UI state với useState
✅ Xử lý side effects với useEffect
✅ Xử lý events và form inputs trong React
✅ Render lists hiệu quả với keys
✅ Áp dụng các pattern conditional rendering
Thiết Lập Môi Trường
Bạn không cần cấu hình bất cứ điều gì để bắt đầu học React. Hãy dùng một trong các tùy chọn sau:
Tùy chọn A: Playground trực tuyến (không cần setup)
Truy cập react.new — một sandbox React sẵn sàng dùng ngay trên trình duyệt.
Tùy chọn B: Project cục bộ với Vite (khuyến nghị để học)
npm create vite@latest react-fundamentals -- --template react
cd react-fundamentals
npm install
npm run devMở http://localhost:5173 và bạn đã chạy React.
Ở phần sau của series (Bài RN-4), bạn sẽ chuyển sang Next.js. Hiện tại, Vite là cách nhanh nhất để chạy React thuần trên máy cục bộ.
React Là Gì Và Tại Sao Nó Ra Đời?
Trước khi viết code, hãy hiểu vấn đề mà React giải quyết.
Vấn Đề: Đồng Bộ UI với Dữ Liệu
Hãy tưởng tượng một giỏ hàng. Khi người dùng thêm một sản phẩm, biểu tượng giỏ hàng phải cập nhật số lượng, panel giỏ hàng phải hiển thị sản phẩm mới, và tổng giá phải tính lại — tất cả cùng một lúc.
Với JavaScript thuần, bạn sẽ phải tìm từng phần tử DOM và cập nhật thủ công. Điều này trở thành cơn ác mộng bảo trì khi ứng dụng phát triển. Đồng bộ UI với dữ liệu thay đổi là thách thức cốt lõi của phát triển frontend.
Giải Pháp của React: Declarative UI
React lật ngược mô hình. Thay vì cập nhật DOM theo từng bước, bạn mô tả UI trông như thế nào với một state cụ thể, và React tự xử lý các cập nhật DOM.
// Imperative (JS thuần) — bạn quản lý DOM
document.getElementById('count').textContent = count;
document.getElementById('cart').classList.add('visible');
// Declarative (React) — bạn mô tả kết quả
function Cart({ items }) {
return (
<div className={items.length > 0 ? 'cart visible' : 'cart'}>
<span>{items.length}</span>
</div>
);
}Khi items thay đổi, React tự động render lại Cart. Bạn không cần chạm vào DOM.
Virtual DOM
React duy trì một bản sao nhẹ của DOM trong bộ nhớ — Virtual DOM. Khi state thay đổi, React:
- Render lại component thành cây Virtual DOM mới
- So sánh với cây cũ (reconciliation)
- Chỉ áp dụng những thay đổi tối thiểu lên real DOM
Điều này nhanh. Và quan trọng hơn, nó cho phép bạn viết code declarative mà không cần nghĩ đến DOM manipulation.
JSX: HTML trong JavaScript
JSX là cú pháp React dùng để mô tả UI. Nó trông giống HTML nhưng compile thành các lời gọi hàm JavaScript thông thường.
// JSX
const element = <h1 className="title">Xin chào, React!</h1>;
// Nó compile thành (bạn không bao giờ viết cái này)
const element = React.createElement('h1', { className: 'title' }, 'Xin chào, React!');Các Quy Tắc JSX
1. Trả về một phần tử gốc duy nhất
// ❌ Hai phần tử anh em — không hợp lệ
return (
<h1>Tiêu đề</h1>
<p>Nội dung</p>
);
// ✅ Bọc trong một div
return (
<div>
<h1>Tiêu đề</h1>
<p>Nội dung</p>
</div>
);
// ✅ Hoặc dùng Fragment (không tạo thêm node DOM)
return (
<>
<h1>Tiêu đề</h1>
<p>Nội dung</p>
</>
);2. Dùng className thay vì class
// ❌ Attribute HTML
<div class="container">
// ✅ Attribute JSX
<div className="container">3. Tự đóng các thẻ không có children
<img src="photo.jpg" alt="Ảnh" />
<input type="text" />
<br />4. Biểu thức JavaScript nằm trong {}
const name = "Alice";
const age = 30;
return (
<div>
<h1>Xin chào, {name}!</h1>
<p>Tuổi: {age}</p>
<p>Năm sinh: {new Date().getFullYear() - age}</p>
<p>{age >= 18 ? 'Người lớn' : 'Trẻ vị thành niên'}</p>
</div>
);5. Attributes dùng camelCase
<input
type="text"
onChange={handleChange}
autoComplete="off"
tabIndex={1}
/>Components: Các Khối Xây Dựng
Một React component là một hàm JavaScript trả về JSX. Components là đơn vị cốt lõi của React — mọi thứ đều là component.
Component Đầu Tiên Của Bạn
function Greeting() {
return <h1>Xin chào, thế giới!</h1>;
}Đó là tất cả. Một component chỉ là một hàm. React gọi nó và đặt JSX được trả về vào DOM.
Quy Tắc Component
- Tên phải bắt đầu bằng chữ hoa —
Greeting, không phảigreeting. React dùng điều này để phân biệt components với HTML tags. - Phải trả về JSX (hoặc
nullđể không render gì) - Có thể được dùng như HTML tags trong các components khác
Kết Hợp Components
Components lồng vào nhau, giống như các phần tử HTML:
function Avatar() {
return <img src="/avatar.png" alt="Ảnh đại diện" className="avatar" />;
}
function UserBio() {
return (
<div className="bio">
<p>Lập trình viên. Mê cà phê.</p>
</div>
);
}
function UserCard() {
return (
<div className="card">
<Avatar />
<UserBio />
</div>
);
}
function App() {
return (
<main>
<h1>Thành Viên Nhóm</h1>
<UserCard />
<UserCard />
<UserCard />
</main>
);
}Đây là cây component React — toàn bộ UI của bạn là một cây components.
Props: Truyền Dữ Liệu cho Components
Props (viết tắt của properties) cho phép bạn truyền dữ liệu từ component cha xuống con. Chúng giúp components có thể tái sử dụng.
Props Cơ Bản
function Greeting({ name, role }) {
return (
<div>
<h2>Xin chào, {name}!</h2>
<p>Vai trò: {role}</p>
</div>
);
}
function App() {
return (
<div>
<Greeting name="Alice" role="Admin" />
<Greeting name="Bob" role="Biên tập viên" />
<Greeting name="Carol" role="Người xem" />
</div>
);
}Props Mặc Định
function Button({ label, variant = 'primary', disabled = false }) {
return (
<button className={`btn btn-${variant}`} disabled={disabled}>
{label}
</button>
);
}
// Dùng giá trị mặc định
<Button label="Lưu" />
// Ghi đè giá trị mặc định
<Button label="Xóa" variant="danger" disabled={true} />Prop children
Bất kỳ JSX nào được đặt giữa thẻ mở và đóng của component sẽ trở thành prop children:
function Card({ children, title }) {
return (
<div className="card">
<h3 className="card-title">{title}</h3>
<div className="card-body">{children}</div>
</div>
);
}
// Cách dùng
<Card title="Hồ Sơ">
<p>Tên: Alice</p>
<p>Email: [email protected]</p>
</Card>Props Là Read-Only
Không bao giờ sửa đổi props bên trong component. Props chỉ chảy một chiều — từ cha xuống con. Một component chỉ có thể đọc props, không bao giờ thay đổi chúng.
// ❌ Không bao giờ làm điều này
function BadComponent({ count }) {
count = count + 1; // Thay đổi props — sai!
return <p>{count}</p>;
}
// ✅ Dùng state cho các giá trị có thể thay đổi
function GoodComponent({ initialCount }) {
const [count, setCount] = useState(initialCount);
return <p>{count}</p>;
}State: Làm Components Trở Nên Reactive
Props là dữ liệu bên ngoài được truyền vào. State là dữ liệu nội bộ mà component sở hữu và có thể thay đổi. Khi state thay đổi, React render lại component.
useState
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0); // Giá trị ban đầu: 0
return (
<div>
<p>Đếm: {count}</p>
<button onClick={() => setCount(count + 1)}>Tăng</button>
<button onClick={() => setCount(count - 1)}>Giảm</button>
<button onClick={() => setCount(0)}>Đặt lại</button>
</div>
);
}useState trả về một mảng với hai phần tử:
- Giá trị state hiện tại (
count) - Hàm setter (
setCount) — gọi hàm này để cập nhật giá trị
Cập Nhật State Là Bất Đồng Bộ
React gộp các cập nhật state để tối ưu hiệu năng. Không bao giờ dựa vào state được cập nhật ngay lập tức sau khi gọi setter:
// ❌ State cũ — count có thể không phản ánh giá trị mới nhất
function Counter() {
const [count, setCount] = useState(0);
function handleTripleClick() {
setCount(count + 1); // Cả ba đều dùng count cũ
setCount(count + 1);
setCount(count + 1);
// Kết quả: count chỉ tăng từ 0 lên 1, không phải 3
}
}
// ✅ Functional update — luôn dùng state mới nhất
function Counter() {
const [count, setCount] = useState(0);
function handleTripleClick() {
setCount(prev => prev + 1); // Dùng giá trị mới nhất mỗi lần
setCount(prev => prev + 1);
setCount(prev => prev + 1);
// Kết quả: count tăng từ 0 lên 3 ✅
}
}State Object
function ProfileForm() {
const [user, setUser] = useState({
name: '',
email: '',
age: 0,
});
return (
<form>
<input
value={user.name}
onChange={e => setUser(prev => ({ ...prev, name: e.target.value }))}
placeholder="Tên"
/>
<input
value={user.email}
onChange={e => setUser(prev => ({ ...prev, email: e.target.value }))}
placeholder="Email"
/>
</form>
);
}Đặt State Ở Đâu
Kỹ năng React quan trọng là quyết định component nào nên sở hữu từng phần state.
Quy tắc: Đặt state ở tổ tiên chung thấp nhất của tất cả components cần nó.
// ❌ State bị nhân đôi ở hai components — sẽ không đồng bộ
function ComponentA() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}
function ComponentB() {
const [count, setCount] = useState(0); // Count khác!
return <p>Đếm: {count}</p>;
}
// ✅ State được nâng lên component cha — nguồn sự thật duy nhất
function Parent() {
const [count, setCount] = useState(0);
return (
<>
<ComponentA count={count} onIncrement={() => setCount(c => c + 1)} />
<ComponentB count={count} />
</>
);
}Pattern này được gọi là lifting state up — nó là nền tảng của kiến trúc React.
Xử Lý Events
React xử lý events với attributes camelCase và tham chiếu hàm (không phải chuỗi):
// ❌ Kiểu HTML
<button onclick="handleClick()">Nhấn vào đây</button>
// ✅ Kiểu React
<button onClick={handleClick}>Nhấn vào đây</button>Các Pattern Event Handler
function EventExamples() {
// Arrow function inline
const handleClick = () => console.log('Đã nhấn!');
// Với event object
const handleInput = (event) => {
console.log(event.target.value);
};
// Truyền đối số
const handleItemClick = (id) => {
console.log('Đã nhấn vào item:', id);
};
return (
<div>
<button onClick={handleClick}>Nhấn vào đây</button>
<input onChange={handleInput} />
{/* ✅ Arrow function để truyền đối số */}
<button onClick={() => handleItemClick(42)}>Item 42</button>
{/* ❌ Cái này gọi handleItemClick ngay khi render! */}
<button onClick={handleItemClick(42)}>Sai!</button>
</div>
);
}Controlled Inputs
Các form trong React dùng controlled inputs — giá trị input được điều khiển bởi state:
function SearchBar() {
const [query, setQuery] = useState('');
const handleSubmit = (e) => {
e.preventDefault(); // Ngăn tải lại trang
console.log('Tìm kiếm:', query);
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={query} // Được điều khiển bởi state
onChange={e => setQuery(e.target.value)} // Cập nhật state
placeholder="Tìm kiếm..."
/>
<button type="submit">Tìm</button>
<p>Từ khóa: {query}</p>
</form>
);
}Conditional Rendering
React không có cú pháp template như v-if hay *ngIf. Bạn dùng JavaScript thông thường:
Toán Tử Ternary
function UserStatus({ isLoggedIn }) {
return (
<div>
{isLoggedIn ? (
<p>Chào mừng trở lại!</p>
) : (
<p>Vui lòng đăng nhập.</p>
)}
</div>
);
}Logical AND (&&)
Render gì đó chỉ khi điều kiện đúng:
function Notification({ hasMessages, messageCount }) {
return (
<div>
<h1>Hộp thư</h1>
{hasMessages && (
<p>Bạn có {messageCount} tin nhắn chưa đọc.</p>
)}
</div>
);
}Lưu ý:
0 && <Component />render số0, không phải không có gì! Dùng!!count && ...hoặc ternary thay thế.
Early Return
Với điều kiện phức tạp, return sớm giúp components dễ đọc hơn:
function UserDashboard({ user, isLoading, error }) {
if (isLoading) return <p>Đang tải...</p>;
if (error) return <p>Lỗi: {error.message}</p>;
if (!user) return null;
return (
<div>
<h1>Chào mừng, {user.name}</h1>
{/* ... nội dung dashboard */}
</div>
);
}Render Lists
Dùng .map() để chuyển đổi mảng thành các phần tử JSX:
const fruits = ['Táo', 'Chuối', 'Cherry'];
function FruitList() {
return (
<ul>
{fruits.map(fruit => (
<li key={fruit}>{fruit}</li>
))}
</ul>
);
}Prop key
Mỗi item trong list cần một prop key duy nhất. React dùng keys để theo dõi những item nào đã thay đổi, được thêm vào, hoặc bị xóa.
const users = [
{ id: 1, name: 'Alice', role: 'Admin' },
{ id: 2, name: 'Bob', role: 'Biên tập viên' },
{ id: 3, name: 'Carol', role: 'Người xem' },
];
function UserList() {
return (
<ul>
{users.map(user => (
// ✅ Dùng ID ổn định và duy nhất làm key
<li key={user.id}>
{user.name} — {user.role}
</li>
))}
</ul>
);
}Quy tắc key:
- Keys phải duy nhất trong các phần tử anh em (không cần toàn cục)
- Dùng IDs ổn định từ dữ liệu của bạn (database IDs, slugs, v.v.)
- Không bao giờ dùng index mảng làm key khi list có thể sắp xếp lại hoặc items có thể được thêm/xóa — nó gây ra các lỗi tinh vi
// ❌ Index làm key — lỗi khi list sắp xếp lại
{items.map((item, index) => (
<Item key={index} data={item} />
))}
// ✅ ID ổn định làm key
{items.map(item => (
<Item key={item.id} data={item} />
))}useEffect: Quản Lý Side Effects
Components nên thuần túy — với cùng props và state, chúng luôn trả về cùng JSX. Nhưng ứng dụng thực cần side effects: fetch dữ liệu, thiết lập subscriptions, cập nhật document title.
useEffect xử lý tất cả những điều này.
Cách Dùng Cơ Bản
import { useState, useEffect } from 'react';
function DocumentTitle({ page }) {
useEffect(() => {
document.title = `Trang: ${page}`;
}, [page]); // Chạy khi `page` thay đổi
return <h1>Trang hiện tại: {page}</h1>;
}Mảng Dependency
Đối số thứ hai của useEffect kiểm soát khi nào nó chạy:
// ✅ Chạy sau mỗi lần render
useEffect(() => {
console.log('Đã render');
});
// ✅ Chạy một lần, chỉ khi mount
useEffect(() => {
console.log('Đã mount');
}, []);
// ✅ Chạy khi `userId` hoặc `filter` thay đổi
useEffect(() => {
fetchUser(userId, filter);
}, [userId, filter]);Fetch Dữ Liệu
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
setLoading(true);
setError(null);
fetch(`https://api.example.com/users/${userId}`)
.then(res => {
if (!res.ok) throw new Error('Không tìm thấy người dùng');
return res.json();
})
.then(data => {
setUser(data);
setLoading(false);
})
.catch(err => {
setError(err.message);
setLoading(false);
});
}, [userId]); // Fetch lại khi userId thay đổi
if (loading) return <p>Đang tải...</p>;
if (error) return <p>Lỗi: {error}</p>;
return (
<div>
<h2>{user.name}</h2>
<p>{user.email}</p>
</div>
);
}Cleanup
Một số effects cần cleanup — để tránh memory leaks và stale updates:
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setSeconds(prev => prev + 1);
}, 1000);
// ✅ Cleanup: xóa interval khi component unmount
return () => clearInterval(interval);
}, []); // Mảng rỗng — thiết lập một lần, dọn dẹp khi unmount
return <p>Thời gian trôi qua: {seconds}s</p>;
}function SearchResults({ query }) {
const [results, setResults] = useState([]);
useEffect(() => {
let cancelled = false; // Flag để ngăn stale updates
fetch(`/api/search?q=${query}`)
.then(res => res.json())
.then(data => {
if (!cancelled) setResults(data); // Chỉ cập nhật nếu vẫn còn liên quan
});
return () => { cancelled = true; }; // Cleanup khi render tiếp theo
}, [query]);
return <ul>{results.map(r => <li key={r.id}>{r.title}</li>)}</ul>;
}Các Lỗi useEffect Phổ Biến
// ❌ Thiếu dependency — stale closure
useEffect(() => {
fetchData(userId); // userId được dùng nhưng không có trong deps array
}, []); // Lỗi: không bao giờ fetch lại khi userId thay đổi
// ✅ Thêm tất cả dependencies
useEffect(() => {
fetchData(userId);
}, [userId]);
// ❌ Object trong dependency array — gây vòng lặp vô hạn
useEffect(() => {
fetchData(options);
}, [options]); // options là object mới mỗi lần render!
// ✅ Dùng giá trị primitive hoặc chuyển object vào trong effect
useEffect(() => {
const options = { limit: 10, page: currentPage };
fetchData(options);
}, [currentPage]);Kết Hợp Tất Cả: Quản Lý Task
Hãy xây dựng một trình quản lý task nhỏ kết hợp mọi thứ từ bài này:
import { useState, useEffect } from 'react';
function TaskItem({ task, onToggle, onDelete }) {
return (
<li className={task.done ? 'done' : ''}>
<input
type="checkbox"
checked={task.done}
onChange={() => onToggle(task.id)}
/>
<span>{task.text}</span>
<button onClick={() => onDelete(task.id)}>Xóa</button>
</li>
);
}
function TaskForm({ onAdd }) {
const [text, setText] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
if (!text.trim()) return;
onAdd(text.trim());
setText('');
};
return (
<form onSubmit={handleSubmit}>
<input
value={text}
onChange={e => setText(e.target.value)}
placeholder="Thêm task..."
/>
<button type="submit">Thêm</button>
</form>
);
}
function TaskManager() {
const [tasks, setTasks] = useState([]);
const [filter, setFilter] = useState('all'); // 'all' | 'active' | 'done'
// Lưu tasks vào localStorage
useEffect(() => {
const saved = localStorage.getItem('tasks');
if (saved) setTasks(JSON.parse(saved));
}, []);
useEffect(() => {
localStorage.setItem('tasks', JSON.stringify(tasks));
}, [tasks]);
const addTask = (text) => {
setTasks(prev => [
...prev,
{ id: Date.now(), text, done: false },
]);
};
const toggleTask = (id) => {
setTasks(prev =>
prev.map(t => t.id === id ? { ...t, done: !t.done } : t)
);
};
const deleteTask = (id) => {
setTasks(prev => prev.filter(t => t.id !== id));
};
const filteredTasks = tasks.filter(t => {
if (filter === 'active') return !t.done;
if (filter === 'done') return t.done;
return true;
});
return (
<div className="task-manager">
<h1>Tasks ({tasks.filter(t => !t.done).length} còn lại)</h1>
<TaskForm onAdd={addTask} />
<div className="filters">
{[
{ key: 'all', label: 'Tất cả' },
{ key: 'active', label: 'Chưa xong' },
{ key: 'done', label: 'Đã xong' },
].map(f => (
<button
key={f.key}
onClick={() => setFilter(f.key)}
className={filter === f.key ? 'active' : ''}
>
{f.label}
</button>
))}
</div>
{filteredTasks.length === 0 ? (
<p>Không có task nào.</p>
) : (
<ul>
{filteredTasks.map(task => (
<TaskItem
key={task.id}
task={task}
onToggle={toggleTask}
onDelete={deleteTask}
/>
))}
</ul>
)}
</div>
);
}
export default TaskManager;Ví dụ đơn này minh họa:
- Nhiều components (
TaskItem,TaskForm,TaskManager) - Truyền props và children
useStatecho tasks, filter và form inputuseEffectđể lưu localStorage- Controlled inputs
- Event handlers
- Render list với keys
- Conditional rendering
Tư Duy React Developer
Trước khi chuyển sang Phase 2, hãy thấm nhuần các pattern tư duy sau:
Tư Duy Theo Component
Phân tách bất kỳ UI nào thành cây components. Tự hỏi:
- Component này cần dữ liệu gì? (props)
- Component này sở hữu và thay đổi gì? (state)
- Tôi có thể trích xuất gì thành component nhỏ hơn, tái sử dụng được?
Dữ Liệu Chảy Xuống, Events Chảy Lên
Dữ liệu chảy xuống qua props. Thay đổi chảy lên qua các callback function được truyền dưới dạng props. Không bao giờ ngược lại.
Giữ Components Thuần Túy
Output của component chỉ nên phụ thuộc vào props và state của nó — không có dependency ẩn, không có giá trị ngẫu nhiên, không trực tiếp thay đổi dữ liệu bên ngoài.
State Là Một Snapshot
Khi bạn gọi setCount(count + 1), React không thay đổi count ngay lập tức. Nó lên lịch re-render. Lần tiếp theo component render, nó nhận được count mới. Hãy nghĩ state như một snapshot của một khoảnh khắc.
Bài Tập Thực Hành
Làm qua các bài tập này để củng cố các khái niệm Phase 1:
Bài tập 1 — Toggle Xây dựng component với button toggle giữa hiển thị và ẩn đoạn văn bản.
Bài tập 2 — Bộ đếm với bước nhảy Xây dựng bộ đếm nơi người dùng có thể đặt số bước nhảy (1, 5, 10) và tăng/giảm theo bước đó.
Bài tập 3 — Danh sách mua sắm Xây dựng danh sách mua sắm nơi người dùng có thể thêm items, đánh dấu hoàn thành và xóa. Hiển thị số lượng items chưa đánh dấu.
Bài tập 4 — Fetch & Hiển thị
Fetch danh sách bài đăng từ https://jsonplaceholder.typicode.com/posts và hiển thị chúng. Hiển thị trạng thái loading khi đang fetch và trạng thái lỗi nếu request thất bại.
Bài tập 5 — Color Picker Xây dựng component với ba sliders (R, G, B, 0–255). Hiển thị ô màu cập nhật theo thời gian thực khi sliders thay đổi.
Tóm Tắt
Trong Phase 1, bạn đã học các khái niệm React nền tảng:
| Khái Niệm | Làm Gì |
|---|---|
| JSX | Cú pháp HTML-like compile thành các lời gọi React.createElement |
| Components | Hàm trả về JSX — các khối xây dựng của React UI |
| Props | Dữ liệu read-only được truyền từ cha xuống con |
State (useState) | Dữ liệu nội bộ có thể thay đổi — thay đổi kích hoạt re-renders |
useEffect | Chạy side effects (fetch, timers, subscriptions) sau khi render |
| Events | Xử lý tương tác người dùng với event attributes camelCase |
| Lists & Keys | Render mảng với .map(), dùng keys ổn định |
| Conditional rendering | Ternary, &&, hoặc early return cho UI có điều kiện |
Các khái niệm này là nền tảng hoàn chỉnh. Mọi pattern React nâng cao đều xây dựng trên chúng.
Tiếp Theo Là Gì
Trong Bài RN-3: Phase 2 — Hệ Sinh Thái React, bạn sẽ mở rộng nền tảng này với:
- Client-side routing với React Router
- Global state management
- Form libraries (React Hook Form)
- Data fetching với SWR hoặc TanStack Query
- Component libraries (Tailwind CSS, shadcn/ui)
Chỉ Mục Series
| Bài | Tiêu Đề | Trạng Thái |
|---|---|---|
| RN-1 | React.js & Next.js Roadmap | ✅ Hoàn thành |
| RN-2 | Phase 1: Nền Tảng React | ✅ Bạn đang ở đây |
| RN-3 | Phase 2: Hệ Sinh Thái React | Sắp Ra Mắt |
| RN-4 | Phase 3: Next.js Full-Stack | Sắp Ra Mắt |
| RN-5 | Deep Dive: Thành Thạo React Hooks | Sắp Ra Mắt |
| RN-6 | Deep Dive: State Management | Sắp Ra Mắt |
| RN-7 | Deep Dive: App Router & Server Components | Sắp Ra Mắt |
| RN-8 | Deep Dive: Các Pattern Data Fetching | Sắp Ra Mắt |
| RN-9 | Deep Dive: Tối Ưu Hiệu Năng | Sắp Ra Mắt |
| RN-10 | Deep Dive: Authentication trong Next.js | Sắp Ra Mắt |
| RN-11 | Deep Dive: Testing React & Next.js | Sắp Ra Mắt |
| RN-12 | Deep Dive: Deploy Ứng Dụng Next.js | Sắp Ra Mắt |
📬 Đăng ký nhận bản tin
Nhận những bài viết mới nhất qua email mỗi tuần. Không spam, hủy đăng ký bất cứ lúc nào.
Chúng tôi tôn trọng quyền riêng tư của bạn. Hủy đăng ký bất cứ lúc nào.
💬 Comments
Đăng nhập để bình luận
Chúng tôi sẽ không đăng bất cứ điều gì mà không có sự cho phép của bạn.