Anh em mình code React chắc không lạ gì cảnh component ngày càng phình to, logic state và side effect đan xen nhau như mớ bòng bong, đặc biệt là khi chuyển từ class component qua. Ngày xưa mình cũng vật lộn với this.state và một rổ lifecycle methods. Từ khi React 16.8 ra đời với Hooks, cuộc đời developer chúng mình như sang một trang mới. Trọng tâm của sự thay đổi đó chính là useState và useEffect – hai “siêu anh hùng” trong bài React Hooks useState useEffect hướng dẫn này – giúp code sạch hơn, logic dễ theo dõi hơn hẳn.
Quản lý state chưa bao giờ dễ thế với useState
Quản lý trạng thái trong React Hooks đã trở nên vô cùng trực quan nhờ useState. Nó loại bỏ hoàn toàn sự phức tạp của từ khóa this và giúp bạn tách bạch các luồng dữ liệu một cách độc lập.
React Hooks là gì mà “thần thánh” vậy?
React Hooks là các hàm đặc biệt cho phép bạn “móc” (hook) vào các tính năng cốt lõi của React như quản lý state và lifecycle ngay bên trong Functional Components mà không cần viết Class.
Trước đây, để lưu trữ dữ liệu thay đổi trên giao diện, chúng ta bắt buộc phải dùng Class Components. Điều này làm code dài dòng, khó đọc và cực kỳ khó tái sử dụng logic giữa các component với nhau. Sự ra đời của Hooks từ phiên bản React 16.8 đã thay đổi hoàn toàn cục diện phát triển web. Nó giúp Functional Components trở nên mạnh mẽ và linh hoạt không kém gì Class. Nếu bạn đang chập chững bước vào thế giới này, một lộ trình Học React JS từ đầu cho người mới sẽ là bước đệm tuyệt vời. Tại Phạm Hải, qua quá trình đào tạo nhiều thế hệ lập trình viên, mình luôn nhấn mạnh rằng việc hiểu sâu bản chất của Hooks là chìa khóa để viết code React hiện đại.
useState là gì? Nói lời tạm biệt với this.state
useState là một Hook cơ bản trong React cho phép bạn khai báo, đọc và cập nhật trạng thái (state) cục bộ trực tiếp bên trong một Functional Component.
Khi gọi useState, nó sẽ trả về cho bạn một mảng gồm đúng hai phần tử: giá trị state hiện tại và một hàm (setter function) dùng để cập nhật giá trị đó. Cú pháp này tận dụng tính năng destructuring rất thanh lịch của JavaScript. Nếu bạn chưa quen với cách viết này, hãy xem lại ngay các ES6 JavaScript tính năng mới cần biết. Khác với this.state rườm rà gộp chung mọi thứ vào một object lớn, useState cho phép khai báo trực tiếp và độc lập từng biến (ví dụ: một biến cho tên, một biến cho tuổi). Điều này giúp việc theo dõi luồng dữ liệu tường minh hơn rất nhiều.
Cách sử dụng useState trong React: Từ cơ bản đến nâng cao
Cách sử dụng useState trong React bắt đầu bằng việc import nó từ thư viện ‘react’, sau đó gọi hook này ở ngay dòng đầu tiên của component với một giá trị khởi tạo tùy ý.
Ví dụ cơ bản nhất là làm một bộ đếm: const [count, setCount] = useState(0);. Mỗi khi user click và bạn gọi hàm setCount(count + 1), React sẽ tự động kích hoạt quá trình Render/Re-render để cập nhật con số mới lên giao diện. Tuy nhiên, có một kỹ thuật nâng cao bạn bắt buộc phải biết: sử dụng Callback function khi cập nhật state. Thay vì viết setCount(count + 1), hãy dùng setCount(prevCount => prevCount + 1). Cách viết này giúp lấy được giá trị state mới nhất một cách an toàn, đặc biệt khi có nhiều thao tác cập nhật diễn ra liên tiếp. Quá trình này đòi hỏi bạn phải nắm vững cách JS xử lý hàm, nên việc ôn luyện Học JavaScript cơ bản cho người mới 2026 là nền tảng không bao giờ thừa.
Những sai lầm “chết người” khi dùng useState và cách né
Sai lầm phổ biến nhất là cập nhật state trực tiếp (mutate state) thay vì dùng hàm setter, hoặc khởi tạo state với các hàm tính toán nặng nề gây nghẽn hiệu suất.
Khi làm việc với object hoặc mảng trong state, tuyệt đối không được sửa trực tiếp kiểu state.user = 'Hải'. Bạn luôn phải tạo một bản sao mới (clone) rồi mới truyền vào hàm set. Để xử lý mảng hiệu quả và không làm thay đổi mảng gốc, các kỹ thuật JavaScript Array methods map filter reduce chính là vũ khí không thể thiếu. Ngoài ra, để React Hooks tối ưu hiệu suất, nếu giá trị khởi tạo ban đầu đòi hỏi tính toán phức tạp (ví dụ đọc từ localStorage), hãy truyền một function vào useState (được gọi là lazy initialization). Bằng cách này, hàm tính toán sẽ chỉ chạy đúng một lần duy nhất ở lần render đầu tiên.
Xử lý side effect gọn gàng bằng useEffect

Bên cạnh state, việc tương tác với thế giới bên ngoài component cũng quan trọng không kém. Xử lý side effect trong React Hooks được quy chuẩn hóa một cách thanh lịch thông qua useEffect.
useEffect là gì? Thay thế hoàn hảo cho lifecycle methods
useEffect là một Hook cho phép bạn thực hiện các tác vụ phụ (side effects) trong Functional Component, đóng vai trò thay thế cho các lifecycle methods cũ như componentDidMount, componentDidUpdate, và componentWillUnmount.
Side Effects là những thao tác tác động ra khỏi phạm vi của một component, ví dụ như gọi API lấy dữ liệu, thao tác trực tiếp với DOM, hoặc thiết lập các bộ đếm thời gian (timers). Việc gom chung các logic này vào useEffect giúp code liên quan đến một tính năng không bị chia cắt rải rác. Nếu bạn đang xây dựng các hiệu ứng phức tạp cần can thiệp trực tiếp vào giao diện, kiến thức về DOM JavaScript thao tác phần tử HTML sẽ kết hợp hoàn hảo với Hook này để tạo ra trải nghiệm người dùng mượt mà.
Cách sử dụng useEffect trong React: Dependency array không còn là nỗi ám ảnh
Cách sử dụng useEffect trong React chuẩn xác nhất là truyền vào nó một hàm callback chứa logic side effect và một Dependency array để kiểm soát chặt chẽ thời điểm effect đó được phép chạy lại.
Dependency array trong useEffect chính là thứ quyết định “sinh tử” của app.
- Nếu bạn để mảng rỗng
[], effect chạy đúng 1 lần duy nhất khi component xuất hiện (mount). - Nếu bạn quên không truyền mảng, effect sẽ chạy lại sau mỗi lần render – đây là nguyên nhân số 1 gây ra lỗi infinite loop (vòng lặp vô hạn) làm treo trình duyệt.
- Nếu có biến trong mảng (Dependencies), effect chỉ chạy lại khi một trong các biến đó thay đổi giá trị.
Theo kinh nghiệm 10 năm của mình, việc quản lý mảng dependency sai cách là lỗi phổ biến nhất của các bạn mới. Hãy luôn kiểm tra kỹ xem những biến nào được dùng bên trong effect thì phải đưa hết vào mảng này.
Ví dụ thực tế: Dùng useEffect để gọi API như dân chuyên
Để thực hiện Data fetching một cách chuẩn mực, bạn đặt logic gọi API bên trong useEffect với dependency array rỗng, đảm bảo dữ liệu chỉ được tải một lần khi component vừa render xong.
Đây là một React Hooks ví dụ thực tế cực kỳ kinh điển. Kết hợp React Hooks với API luôn yêu cầu xử lý bất đồng bộ. Vì bản thân hàm callback của useEffect không được phép là một async function, bạn cần khai báo một hàm async nhỏ bên trong nó rồi mới gọi thực thi. Để hiểu sâu hơn về cơ chế chờ đợi phản hồi này, bạn nên nắm vững Async Await Promise JavaScript dễ hiểu. Trong thực tế, chúng ta thường dùng Fetch API gọi REST API bằng JavaScript ngay bên trong hàm async này để lấy dữ liệu từ server và lưu vào state. Mặc dù tính đến năm 2026, React 19 đã bổ sung thêm hook use() mới cho Server Components, nhưng ở môi trường Client, useEffect vẫn là tiêu chuẩn vàng,.
Đừng quên cleanup function trong useEffect để tránh memory leak!
Cleanup function là một hàm được return từ bên trong useEffect, có nhiệm vụ dọn dẹp các tài nguyên như event listener hay timer trước khi component bị hủy (unmount) hoặc trước khi effect chạy lại lần tiếp theo.
Nếu bạn đăng ký một sự kiện lắng nghe cuộn chuột (window.addEventListener('scroll', ...)) mà quên Clean up, mỗi lần component re-render nó sẽ tạo thêm một listener mới. Tích tụ dần, ứng dụng của bạn sẽ bị rò rỉ bộ nhớ (memory leak) và trở nên giật lag. Việc trả về Cleanup function useEffect là quy tắc bắt buộc để giữ cho ứng dụng khỏe mạnh. Hãy coi nó như việc bạn dọn dẹp sạch sẽ phòng trọ trước khi trả phòng vậy.
So sánh Functional Component (với Hooks) và Class Component

Sự chuyển dịch từ Class sang Functional Component không chỉ là thay đổi cú pháp, mà là một bước tiến lớn về tư duy thiết kế phần mềm trong hệ sinh thái React.
Code trước và sau khi có Hooks: Một trời một vực
So sánh functional component và class component React cho thấy Hooks giúp giảm thiểu đáng kể lượng boilerplate code, loại bỏ hoàn toàn từ khóa this rắc rối và gom nhóm logic theo chức năng.
Dưới đây là bảng so sánh nhanh để bạn thấy sự khác biệt:
| Tiêu chí | Class Component | Functional Component (với Hooks) |
|---|---|---|
| Cú pháp & Độ dài | Dài dòng, nhiều boilerplate code | Ngắn gọn, súc tích, dễ đọc |
| Quản lý State | Dùng this.state và this.setState |
Dùng useState linh hoạt |
| Side Effects | Phân tán ở nhiều Lifecycle methods | Gom chung gọn gàng vào useEffect |
Trong Class, logic gọi API và dọn dẹp thường bị xé lẻ ở componentDidMount và componentWillUnmount. Với Hooks, mọi thứ nằm gọn trong một khối useEffect duy nhất. Code ngắn hơn đồng nghĩa với việc ít bug hơn và bảo trì nhàn hơn rất nhiều.
Tại sao Functional Component lại là xu hướng?
Functional component kết hợp với Hooks trở thành tiêu chuẩn công nghiệp vì chúng nhẹ hơn, dễ viết test hơn và đặc biệt là khả năng chia sẻ logic cực kỳ mạnh mẽ.
Ngoài việc nhận Props đầu vào và trả về giao diện UI, Functional Component giờ đây có thể gánh vác mọi trọng trách phức tạp nhất. Toàn bộ hệ sinh thái React hiện tại, từ tài liệu chính thức đến các thư viện UI nổi tiếng, đều viết dựa trên Hooks. Các bản cập nhật mới nhất của React 19 (năm 2026) với React Compiler tự động tối ưu hóa hiệu suất càng củng cố vị thế độc tôn của Functional Component, giúp chúng chạy mượt mà mà không cần lập trình viên phải can thiệp tối ưu thủ công quá nhiều.
Nâng tầm kỹ năng: Viết Custom Hooks cho riêng mình

Khi đã thành thạo useState và useEffect, bước tiếp theo để trở thành một Senior Developer là biết cách tự tạo ra các Hooks của riêng mình.
Custom Hook là gì và tại sao bạn nên quan tâm?
Custom Hooks trong React thực chất chỉ là các hàm JavaScript thông thường có tên bắt đầu bằng chữ “use” và có thể gọi các Hooks có sẵn khác ở bên trong nó.
Nó giúp bạn trích xuất các logic xử lý phức tạp ra khỏi giao diện UI để tái sử dụng ở hàng chục component khác nhau. Ví dụ, logic theo dõi trạng thái online/offline của người dùng có thể được gói gọn vào một hook tên là useOnlineStatus. Việc tổ chức code module hóa như thế này mang tư duy rất giống với cách chúng ta chia nhỏ file bằng JavaScript Module import export hướng dẫn, góp phần giúp dự án scale (mở rộng) lên dễ dàng mà không bị rối.
Xây dựng một Custom Hook đơn giản để tái sử dụng logic
Để tạo Custom Hook, bạn định nghĩa một function mới, mang các useState và useEffect có chung mục đích vào đó, rồi return về những dữ liệu mà component bên ngoài cần dùng.
Giả sử bạn cần fetch data ở 10 màn hình khác nhau. Thay vì lặp đi lặp lại đoạn code useEffect dài ngoằng, hãy viết một Custom Hook tên là useFetch(url). Hook này sẽ tự động quản lý các state như data, isLoading, error và chỉ trả về kết quả cuối cùng cho component. Đây chính là đỉnh cao của việc áp dụng nguyên tắc DRY (Don’t Repeat Yourself) và viết code sạch trong React.
Tóm lại, thông qua bài React Hooks useState useEffect hướng dẫn này, hy vọng bạn đã thấy hai hook này không chỉ là công cụ mới mà là một cuộc cách mạng trong tư duy viết code. Nắm vững chúng giúp bạn quản lý trạng thái và side effect một cách tường minh, giúp code dễ đọc và dễ bảo trì. Khi đã vững nền tảng, bạn có thể tự tin khám phá Các Hook khác trong React như useContext (tránh truyền props nhiều tầng), useReducer (quản lý state phức tạp), useMemo, useCallback, hoặc useRef để giải quyết các bài toán khó nhằn hơn. Hãy áp dụng những kiến thức này vào dự án thực tế ngay hôm nay để tự mình cảm nhận sự thanh lịch của code!
Bạn đã có kinh nghiệm “đau thương” hay khoảnh khắc “ngộ đạo” nào với useState và useEffect chưa? Hãy chia sẻ ở phần bình luận bên dưới nhé, tại Phạm Hải, chúng mình luôn rất muốn nghe câu chuyện thực tế từ bạn!
Lưu ý: Thông tin trong bài viết này chỉ mang tính chất tham khảo. Để có lời khuyên tốt nhất, vui lòng liên hệ trực tiếp với chúng tôi để được tư vấn cụ thể dựa trên nhu cầu thực tế của bạn.