Trong hành trình tìm hiểu về Front-end, sau khi đã nắm vững những nền tảng quan trọng của JavaScript ở phần 2, chúng ta sẽ bước sang một giai đoạn mới: làm quen với React.js – thư viện JavaScript phổ biến nhất hiện nay để xây dựng giao diện người dùng.
React.js không chỉ giúp việc phát triển ứng dụng web trở nên hiệu quả hơn mà còn thay đổi cách chúng ta tư duy về UI, với những khái niệm quan trọng như component-based architecture, Virtual DOM, state management, v.v. Vậy React.js có gì đặc biệt? Vì sao nó lại trở thành lựa chọn hàng đầu của các lập trình viên Front-end? Hãy cùng khám phá trong bài viết này!
- React.js là gì?
React.js (gọi tắt là React) là một thư viện JavaScript dùng để xây dựng giao diện người dùng (UI), đặc biệt là ứng dụng web single-page (SPA). React giúp phát triển UI hiệu quả hơn bằng cách sử dụng component-based architecture và cập nhật giao diện thông qua Virtual DOM.
- Vì sao nên sử dụng React?
- Tái sử dụng component → Giảm lặp code, dễ bảo trì.
- Hiệu suất cao → Virtual DOM giúp tối ưu quá trình render.
- Hỗ trợ mạnh mẽ từ cộng đồng → Thư viện phổ biến, nhiều tài liệu hỗ trợ.
- Học nhanh nếu đã biết JavaScript → Cú pháp JSX dễ tiếp cận.
- Dễ mở rộng với hệ sinh thái phong phú → Next.js, React Native, Redux, v.v.
- Lịch sử phát triển
- Được phát triển bởi Facebook (Meta) vào năm 2013.
- Ban đầu được sử dụng nội bộ cho Facebook và Instagram.
- Dần trở thành thư viện JavaScript phổ biến nhất trong Front-end.
- Cài đặt và môi trường phát triển
2.1 Yêu cầu hệ thống
- Node.js: Cần cài đặt Node.js (>=14.0.0) để chạy React. Kiểm tra bằng lệnh: node -v
- Trình quản lý gói: Sử dụng npm (mặc định theo Node.js) hoặc yarn
2.2 Cài đặt React.js
Có hai cách phổ biến để tạo dự án React:
- Dùng create-react-app (CRA) là cách đơn giản nhất để bắt đầu một dự án React
npx create-react-app my-app
cd my-app
npm start
📌 CRA tự động thiết lập Webpack, Babel, và các cấu hình cơ bản.
- Dùng Vite (nhanh hơn CRA): Vite giúp khởi động nhanh hơn, phù hợp với dự án hiện đại
npm create vite@latest my-app –template react
cd my-app
npm install
npm run dev
📌 Vite có tốc độ build nhanh hơn CRA và hỗ trợ tốt TypeScript.
2.3. Cấu trúc thư mục cơ bản của React
Sau khi khởi tạo dự án, bạn sẽ thấy cấu trúc như sau:
my-app/
│── node_modules/ # Thư viện cài đặt
│── public/ # Tệp tĩnh (index.html, favicon, v.v.)
│── src/ # Code chính của ứng dụng
│ │── App.js # Component gốc
│ │── index.js # Điểm khởi chạy ứng dụng
│── package.json # Danh sách dependency
│── vite.config.js # (Nếu dùng Vite)
Tất cả code chính nằm trong thư mục src/, nơi bạn sẽ viết component, logic, và xử lý dữ liệu.
- Các khái niệm cốt lõi (basic concept) trong React.js
3.1 JSX – JavaScript XML
- JSX là cú pháp mở rộng cho JavaScript, cho phép viết HTML trong JS.
- JSX không phải HTML mà được biên dịch thành JavaScript.
- Ví dụ:
const element = <h1>Chào mừng đến với React!</h1>;
- JSX giúp code dễ đọc hơn nhưng vẫn có thể sử dụng React.createElement() nếu không muốn dùng JSX.
3.2 Components (Thành phần)
- Component là khối xây dựng của giao diện React.
- Có hai loại component chính:
- Functional Component (Khuyến khích sử dụng)
function Welcome(props) {
return <h1>Xin chào, {props.name}!</h1>;
}
- Class Component (Cũ, ít dùng trong React hiện đại)
class Welcome extends React.Component {
render() {
return <h1>Xin chào, {this.props.name}!</h1>;
}
}
- Props (Thuộc tính): Cho phép truyền dữ liệu từ component cha sang component con.
3.3 State và quản lý state
- State là dữ liệu nội bộ của component, thay đổi state sẽ làm component render lại.
- Functional component dùng useState để quản lý state
import { useState } from ‘react’;
function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>Count: {count}</button>;
}
- So sánh State vs Props:
Thuộc tính | State | Props |
Thay đổi được không? | Có | Không |
Ai quản lý? | Component sở hữu | Component cha truyền xuống |
Render lại component khi thay đổi? | Có | Không |
3.4 Vòng đời của Component (Lifecycle)
- Vòng đời gồm 3 giai đoạn:
- Mounting (Khởi tạo) – Khi component được tạo.
- Updating (Cập nhật) – Khi state hoặc props thay đổi.
- Unmounting (Hủy) – Khi component bị xóa khỏi giao diện
- So sánh Class Component vs Function Component (dùng bảng lifecycle)
Trong React, vòng đời của component khác nhau giữa class component và function component, nhưng mục đích đều là để quản lý cách mà component khởi tạo, cập nhật và hủy bỏ
Phase | Class component | Function Component | Mô tả | ||
Khởi tạo (Mounting) |
constructor | Được gọi khi component được khởi tạo lần đầu tiên. Dùng để khởi tạo state và các phương thức. | |||
static getDerivedStateFromProps | Return JSX | Được gọi trước render đầu tiên để cập nhật state từ props (ít dùng). | |||
render | useEffect(() => {…}, []) | Bắt buộc, trả về giao diện UI của component. | |||
componentDidMount | Được gọi một lần sau khi render đầu tiên, thích hợp cho việc gọi API và gán event listeners. | ||||
Cập nhật (Updating) | static getDerivedStateFromProps | Được gọi trước render mỗi khi props hoặc state thay đổi, cập nhật state từ props. | |||
shouldComponentUpdate | Kiểm soát render lại component khi state hoặc props thay đổi, giúp tối ưu hóa hiệu suất. | ||||
render | Render lại component khi state hoặc props thay đổi. | ||||
getSnapshotBeforeUpdate | Chạy trước khi DOM cập nhật, ghi lại snapshot về giao diện trước khi update. | ||||
componentDidUpdate | Được gọi sau khi component cập nhật xong. Tương tự như componentDidUpdate trong function component. | ||||
|
componentWillUnmount | useEffect(() => { return () => {…}; }, []) | Được gọi khi component chuẩn bị bị hủy, dùng để dọn dẹp event listeners hoặc cancel API calls. | ||
Bắt lỗi (Error Handling) | componentDidCatch | Được gọi khi có lỗi xảy ra trong quá trình render hoặc trong lifecycle methods của child components. |
Lưu ý: Quan trọng nhất trong class Component là method componentDidMount, khi đã render, component được add vào cây DOM ổn định, lúc này thích hợp để call API. useEffect trong function component giúp thay thế các phương thức lifecycle cũ
- Các hook trong ReactJs
Trong React, hooks là một tính năng mạnh mẽ giúp bạn quản lý trạng thái và các hiệu ứng phụ trong functional components, thay thế dần các class components truyền thống. Dưới đây là một số hook phổ biến trong React:
- useState: Dùng để khai báo và quản lý trạng thái trong một functional component.
const [state, setState] = useState(initialValue);
- useEffect: Dùng để thực thi các hiệu ứng phụ, như gọi API, cập nhật DOM, hoặc đăng ký sự kiện khi component render hoặc trạng thái thay đổi.
useEffect(() => {
// Mã chạy khi component mount hoặc khi trạng thái thay đổi
}, [dependencies]); // [dependencies] là danh sách các state hoặc props để theo dõi thay đổi
- useContext: Dùng để truy cập giá trị từ một Context mà không cần phải truyền props qua nhiều cấp độ component.
const value = useContext(MyContext);
- useReducer: Dùng để quản lý trạng thái phức tạp hơn, đặc biệt khi có nhiều hành động thay đổi trạng thái. Tương tự như useState, nhưng thay vì trực tiếp cập nhật trạng thái, bạn sẽ dispatch các hành động.
const [state, dispatch] = useReducer(reducer, initialState);
- useCallback: Dùng để ghi nhớ một hàm đã được khai báo và chỉ tái tạo lại nó khi các phụ thuộc thay đổi. Giúp tối ưu hóa hiệu suất, tránh tái tạo lại các hàm không cần thiết.
const memoizedCallback = useCallback(() => {
// Hàm xử lý
}, [dependencies]);
- useMemo: Dùng để ghi nhớ giá trị tính toán, tránh tính toán lại khi không cần thiết, giúp tối ưu hóa hiệu suất. Thường dùng khi có các phép toán phức tạp.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
- useRef: Dùng để tạo một tham chiếu (reference) đến một DOM element hoặc giữ giá trị giữa các lần render mà không kích hoạt lại render.
const myRef = useRef(initialValue);
- Custom hook
Khái niệm: Custom Hook là một hàm JavaScript trong ReactJS, sử dụng các hook cơ bản (như useState, useEffect, useContext, v.v.) để tái sử dụng logic giữa các component. Nó bắt đầu với tiền tố use theo quy ước của React.
Lợi ích:
- Tái sử dụng logic: Tránh lặp lại logic giống nhau trong nhiều component.
- Tách biệt logic và giao diện: Giúp code rõ ràng hơn, dễ bảo trì.
- Dễ kiểm thử: Custom Hook tách biệt nên việc viết và kiểm thử logic cũng dễ dàng hơn.
- Tăng khả năng đọc code: Chia nhỏ logic thành các đơn vị rõ ràng và có ý nghĩa.
- Quản lý sự kiện trong React
Trong React, sự kiện như onClick, onChange rất dễ sử dụng. Bạn chỉ cần gán chúng cho các phần tử và tạo hàm xử lý tương ứng.
Dưới đây sẽ là 1 chương trình code đơn giản về Xử lý sự kiện với onClick, onChange.
import React, { useState } from ‘react’;
function App() {
const [text, setText] = useState(”);
const handleClick = () => alert(‘Nút đã được ấn! Thông điệp: ‘ + text);
const handleChange = (e) => setText(e.target.value);
return (
<div style={{ padding: ’20px’ }}>
<button
onClick={handleClick}
style={{ padding: ’10px 20px’, backgroundColor: ‘#007BFF’, color: ‘white’, border: ‘none’, borderRadius: ‘5px’ }}
>
Gửi
</button>
<input
type=”text”
value={text}
onChange={handleChange}
placeholder=”Viết gì đó …”
style={{ padding: ’10px’, marginTop: ’10px’, width: ‘100%’, borderRadius: ‘5px’ }}
/>
</div>
);
}
export default App;
Sau khi dùng “npm start” để chạy, bạn hãy nhập đoạn text nào đó và ấn “Gửi”, sẽ có 1 cửa sổ thông báo của window như sau
Sử dụng sự kiện với Arrow Function và Truyền tham số:
import React from ‘react’;
function App() {
const handleClick = (message) => alert(message);
return (
<div style={{ padding: ’20px’ }}>
<button
onClick={() => handleClick(‘Hello!’)}
style={{ padding: ’10px 20px’, backgroundColor: ‘#28A745’, color: ‘white’, border: ‘none’, borderRadius: ‘5px’ }}
>
Click Me
</button>
</div>
);
}
export default App;
Khi bạn click vào nút “Click me” thì cửa sổ hiện ra “Hello!”
- React Router – Điều hướng trang
React Router là thư viện giúp điều hướng giữa các trang trong ứng dụng React mà không cần tải lại trang. react-router-dom là một thư viện cho phép bạn tạo các route trong ứng dụng React chạy trên trình duyệt (client-side routing). Để sử dụng, bạn cần cài đặt thư viện này:
npm install react-router-dom
Thiết lập routing trong React
import React from ‘react’;
import { BrowserRouter as Router, Route, Link, Routes } from ‘react-router-dom’;
function Home() {
return <h2>Home Page</h2>;
}
function About() {
return <h2>About Page</h2>;
}
function App() {
return (
<Router>
<nav>
<Link to=”/”>Home</Link>
<Link to=”/about”>About</Link>
</nav>
<Routes>
<Route path=”/” element={<Home />} />
<Route path=”/about” element={<About />} />
</Routes>
</Router>
);
}
Trong ví dụ trên:
- BrowserRouter (được gọi là Router) là component bao bọc toàn bộ ứng dụng và quản lý việc điều hướng.
- Route định nghĩa các đường dẫn cụ thể, liên kết với các component.
- Link được sử dụng để tạo liên kết giữa các trang mà không phải tải lại trang.’
Route động (Dynamic Routing)
Trong một số trường hợp, bạn cần phải điều hướng đến các route có tham số động, ví dụ như hiển thị thông tin chi tiết của một sản phẩm hoặc người dùng. React Router hỗ trợ dynamic routing qua tham số trong URL.
import React from ‘react’;
import { BrowserRouter as Router, Route, Link, Routes, useParams } from ‘react-router-dom’;
function User() {
const { userId } = useParams();
return <h2>User ID: {userId}</h2>;
}
function App() {
return (
<Router>
<nav>
<ul>
<li>
<Link to=”/user/1″>User 1</Link>
</li>
<li>
<Link to=”/user/2″>User 2</Link>
</li>
</ul>
</nav>
<Routes>
<Route path=”/user/:userId” element={<User />} />
</Routes>
</Router>
);
}
export default App;
Ở đây, đường dẫn /user/:userId là một route động, trong đó :userId là một tham số động. Chúng ta có thể truy cập tham số này thông qua hook useParams
- Quản lý state nâng cao
Quản lý state (State Management) là quá trình kiểm soát và duy trì trạng thái (state) của ứng dụng trong suốt vòng đời của nó. State ở đây là dữ liệu hoặc thông tin mà ứng dụng cần để hoạt động, ví dụ như thông tin người dùng, giao diện người dùng, trạng thái của các component, v.v.
Có rất nhiều cách để quản lý state, tùy vào các trường hợp, chúng ta hãy so sánh 2 cách phổ biến là ContextAPI và Redux
– Context API: Khi nào nên sử dụng?
Context API là cách quản lý state toàn cục cho ứng dụng mà không cần truyền props qua nhiều lớp. Thích hợp cho các ứng dụng nhỏ đến trung bình với state chia sẻ giữa nhiều component.
Khi nào sử dụng:
- Quản lý state đơn giản và không phức tạp.
- Cần chia sẻ state giữa các component ở nhiều cấp độ.
Redux: Tổng quan về cách hoạt động và khi nào nên dùng?
Redux là một thư viện quản lý state toàn cục mạnh mẽ, dựa trên một store duy nhất và các action để cập nhật state. Redux phù hợp với các ứng dụng phức tạp, nơi state cần được theo dõi và quản lý chi tiết.
Khi nào sử dụng:
- Ứng dụng phức tạp, cần quản lý nhiều loại state.
- Cần theo dõi, xử lý side effects (như API calls).
So sánh Redux với Context API
- Context API: Đơn giản, dễ sử dụng cho ứng dụng nhỏ. Tuy nhiên, khi ứng dụng lớn, việc cập nhật state có thể làm giảm hiệu suất.
- Redux: Phức tạp hơn, nhưng mạnh mẽ và phù hợp với ứng dụng lớn, dễ theo dõi và quản lý nhiều state.
- Giao tiếp với API trong React
Khi làm việc với API trong React, bạn có thể sử dụng Fetch API hoặc Axios để gửi yêu cầu và nhận dữ liệu từ server. Bên cạnh đó, bạn thường sẽ dùng useEffect để gọi API và xử lý dữ liệu khi component được render hoặc khi có thay đổi.
Fetch API vs Axios để gọi API
- Fetch API: Là API tích hợp sẵn trong trình duyệt để gọi HTTP requests (GET, POST, v.v.). Fetch trả về một Promise, nhưng bạn cần phải xử lý các lỗi thủ công.
fetch(‘https://api.example.com/data’)
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.log(error))
- Axios: Là thư viện bên ngoài giúp gửi HTTP requests. Axios tự động xử lý các lỗi và trả về kết quả dễ dàng hơn so với Fetch.
import axios from ‘axios’;
axios.get(‘https://api.example.com/data’)
.then(response => console.log(response.data))
.catch(error => console.log(error));
So sánh:
- Fetch: Tích hợp sẵn, đơn giản nhưng cần xử lý lỗi thủ công.
- Axios: Dễ sử dụng hơn, tự động chuyển đổi dữ liệu JSON và xử lý lỗi.
Sử dụng useEffect để fetch dữ liệu từ API
Để gọi API khi component được render hoặc khi có thay đổi, bạn có thể sử dụng hook useEffect trong React.
import React, { useState, useEffect } from ‘react’;
function App() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch(‘https://api.example.com/data’)
.then(response => response.json())
.then(data => {
setData(data);
setLoading(false);
})
.catch(error => {
setError(error);
setLoading(false);
});
}, []); // Chạy 1 lần khi component mount
if (loading) return <p>Loading…</p>;
if (error) return <p>Error: {error.message}</p>;
return <div>{JSON.stringify(data)}</div>;
}
export default App;
Xử lý trạng thái loading, success, error
Để cung cấp trải nghiệm người dùng tốt hơn, bạn nên xử lý các trạng thái loading, success và error khi gọi API:
- loading: Đang tải dữ liệu.
- success: Dữ liệu đã được tải thành công.
- error: Có lỗi khi gọi API (ví dụ: lỗi mạng hoặc API không phản hồi).
const [loading, setLoading] = useState(true);
const [data, setData] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
fetch(‘https://api.example.com/data’)
.then(response => response.json())
.then(data => {
setData(data);
setLoading(false);
})
.catch(error => {
setError(error);
setLoading(false);
});
}, []);
- Virtual DOM là gì?
Virtual DOM (VDOM) là một kỹ thuật giúp cải thiện hiệu suất của ứng dụng React. Khi state hoặc props thay đổi, React sẽ không cập nhật trực tiếp lên DOM thực tế ngay lập tức, mà thay vào đó nó sẽ cập nhật lên một phiên bản ảo của DOM. Sau đó, React sẽ so sánh Virtual DOM với DOM thực tế (quá trình gọi là “reconciliation”) để tìm ra sự khác biệt, và chỉ cập nhật những phần cần thiết trên DOM thực tế.
Lợi ích của Virtual DOM:
- Giảm thiểu thao tác trực tiếp với DOM thực tế, giúp ứng dụng chạy nhanh hơn.
- Cải thiện hiệu suất khi cập nhật UI, đặc biệt trong các ứng dụng lớn.
- Lazy Loading và Code Splitting với React
Lazy Loading là kỹ thuật tải các thành phần (component) hoặc module chỉ khi người dùng cần chúng, thay vì tải tất cả mọi thứ ngay từ đầu. Điều này giúp giảm thời gian tải trang ban đầu và tăng tốc độ tải trang.
Trong React, bạn có thể sử dụng React.lazy() để tải lazy các component.
import React, { Suspense } from ‘react’;
const LazyComponent = React.lazy(() => import(‘./LazyComponent’));
function App() {
return (
<div>
<Suspense fallback={<div>Loading…</div>}>
<LazyComponent />
</Suspense>
</div>
);
}
- React.lazy(): Được sử dụng để lazy load các component.
- Suspense: Bao bọc các component lazy-loaded để hiển thị UI dự phòng (như loading) khi chúng đang được tải.
Code Splitting là kỹ thuật chia mã ứng dụng thành các phần nhỏ hơn (chunks) để tải khi cần thiết. React hỗ trợ code splitting thông qua React.lazy() và React.Suspense, cũng như các công cụ như Webpack.
Kết hợp với lazy loading, code splitting giúp tải những phần của ứng dụng chỉ khi người dùng truy cập vào chúng, giảm thiểu băng thông và thời gian tải.
Ví dụ về code splitting với React Router:
import React, { Suspense } from ‘react’;
import { BrowserRouter as Router, Route, Routes } from ‘react-router-dom’;
const Home = React.lazy(() => import(‘./Home’));
const About = React.lazy(() => import(‘./About’));
function App() {
return (
<Router>
<Suspense fallback={<div>Loading…</div>}>
<Routes>
<Route path=”/” element={<Home />} />
<Route path=”/about” element={<About />} />
</Routes>
</Suspense>
</Router>
);
}
- Virtual DOM giúp tăng hiệu suất React bằng cách giảm thiểu thao tác trực tiếp với DOM thực tế.
- Lazy Loading và Code Splitting là những kỹ thuật tối ưu giúp tải các phần của ứng dụng chỉ khi cần, giảm thiểu thời gian tải trang và giúp ứng dụng chạy nhanh hơn.
Lời Kết
React.js là một thư viện mạnh mẽ và phổ biến giúp xây dựng giao diện người dùng tương tác và hiệu quả. Trong bài viết này, chúng ta đã tìm hiểu các khái niệm cơ bản và những kỹ thuật quan trọng trong React, từ cách tạo ứng dụng, quản lý state, đến tối ưu hóa hiệu suất và giao tiếp với API. Những kiến thức này sẽ giúp bạn bắt đầu với React và xây dựng các ứng dụng mạnh mẽ.
Để tiếp tục phát triển kỹ năng React của mình, bạn có thể tìm hiểu thêm về Hooks nâng cao, Server-side Rendering (SSR) với Next.js, và Testing. Các khóa học và tài liệu tham khảo sẽ là những nguồn tài nguyên hữu ích giúp bạn đi sâu hơn vào các chủ đề nâng cao.
Hy vọng bài viết này đã cung cấp cho bạn những bước đi đầu tiên vững chắc để trở thành một React Developer thành thạo. Hãy tiếp tục học hỏi và thử nghiệm để nâng cao kỹ năng của mình trong việc xây dựng các ứng dụng React. Chân thành cảm ơn bạn đã đọc bài viết!