Spending all my youth coding a React app, when it comes time to build it, the app is slow as a crawl, users complain, and bosses frown. I know that feeling! The good news is that most performance problems in React are not due to "bad" code, but usually revolve around two main culprits: unnecessary re-rendering and oversized bundle sizes. This article will share the most practical tips I learned at Pham Hai to "catch" and "cure" this situation completely, helping your app run smoothly again.
Giảm Re-render Vô Tội Vạ: Bộ Ba Quyền Lực memo, useMemo, useCallback
Bộ ba React.memo, useMemo, và useCallback là các công cụ cốt lõi giúp ngăn chặn quá trình re-render không cần thiết bằng cách ghi nhớ (memoize) component, giá trị tính toán và hàm.
React's Virtual DOM is smart, but it's not perfect. Every time state or props change, React will trigger a top-to-bottom re-rendering cycle. reducing re-render in react is the first step to saving a lagging application. Before diving into memoization, if you don't have a solid foundation yet, reviewing the React Hooks useState useEffect tutorial is a necessary stepping stone. When you understand the component lifecycle, you will know exactly when React performs interface redrawing.
React.memo: "Đóng băng" component khi không có gì thay đổi
React.memo là một Higher-Order Component (HOC) giúp bỏ qua việc render lại một component nếu các props truyền vào không bị thay đổi.
Thay vì phải viết hàm shouldComponentUpdate dài dòng như thời dùng Class Component, React.memo thực hiện so sánh nông (shallow comparison) các props. Nếu giá trị mới và cũ giống nhau, React sẽ sử dụng lại kết quả render trước đó. Tại Phạm Hải, mình luôn khuyên anh em bọc các UI component tĩnh hoặc các component con nằm sâu trong cây DOM bằng React.memo để tiết kiệm chu kỳ render. Tuy nhiên, đừng lạm dụng nó cho mọi component vì bản thân việc so sánh props cũng tiêu tốn một phần nhỏ tài nguyên.
useMemo: Ghi nhớ những kết quả tính toán đắt đỏ
Hook useMemo lưu trữ kết quả của các phép tính phức tạp và chỉ tính toán lại khi các dependencies thay đổi, giúp tiết kiệm tài nguyên CPU.
Đừng dùng useMemo cho mọi phép gán biến thông thường, nó sẽ phản tác dụng vì bộ nhớ phải lưu trữ thêm reference. Hãy dùng nó cho các tác vụ thực sự nặng nề. Ví dụ, khi bạn cần filter hoặc sort một mảng chứa hàng chục ngàn phần tử hiển thị trên bảng. Đây là kỹ thuật tối ưu render react cực kỳ hiệu quả khi làm việc với dữ liệu lớn. Nhờ đó, mỗi khi người dùng gõ text vào ô tìm kiếm, app không phải tính toán lại toàn bộ mảng từ đầu.
useCallback: Tránh tạo lại hàm mới sau mỗi lần render
useCallback trả về một memoized callback, đảm bảo reference của hàm không bị thay đổi giữa các lần render, cực kỳ hữu ích khi truyền hàm xuống child component.
Trong JavaScript, hai hàm có nội dung giống nhau nhưng được định nghĩa ở hai lần render khác nhau sẽ có vùng nhớ (reference) khác nhau. Điều này vô tình làm thay đổi props và phá vỡ lớp bảo vệ của React.memo ở component con. useCallback giải quyết triệt để vấn đề này. Theo cập nhật mới nhất từ React 19 (hiện đã là tiêu chuẩn trong năm 2026), React Compiler có thể tự động hóa một phần việc memoize này. Tuy nhiên, việc nắm vững bản chất vẫn giúp bạn khắc phục react app bị chậm một cách chủ động trong các dự án duy trì code cũ.
"Lose Weight" for Applications: Optimize Bundle Size to Load Pages Faster
Tối ưu hóa bundle size react bằng kỹ thuật chia nhỏ code và tải lười (lazy loading) giúp giảm thời gian tải trang ban đầu, mang lại trải nghiệm mượt mà hơn.
A huge bundle size is the number one "enemy" of page loading speed. The more JavaScript code has to be downloaded and parsed, the longer it takes the browser to display the initial interface. Sometimes, to completely solve the problem of SEO and loading speed, Server Side Rendering (SSR) is the most optimal solution. If you are interested, the article What is Next.js project creation guide will provide detailed instructions on how to start building a React app that renders from the server side.
Code Splitting với React.lazy và Suspense: Cần gì tải đó
Kết hợp React.lazy và Suspense cho phép bạn áp dụng dynamic import, chia nhỏ bundle khổng lồ thành các chunk nhỏ và chỉ tải khi người dùng thực sự cần đến.
Thay vì import toàn bộ component ở ngay đầu file (static import), hãy dùng kỹ thuật Lazy Loading cho các route hoặc các component nặng như thư viện biểu đồ, rich text editor. Việc áp dụng Code Splitting sẽ tách các phần này ra khỏi bundle chính (main bundle). Khi bọc component lười trong thẻ Suspense, bạn có thể hiển thị một UI fallback (ví dụ: spinner loading) trong lúc chờ chunk JavaScript được tải về mạng. Đây là cách tối ưu hiệu suất react js bắt buộc phải có trong mọi dự án thực tế.
Virtualization for long lists: Render only what the user sees
Virtualization technology only renders the DOM elements currently displayed on the screen, helping to free up memory when having to process thousands of items at the same time.
If you render a list of 10,000 lines in the usual way, the virtual DOM and real DOM will immediately overload, causing the browser to crash. Famous libraries like react-window or react-virtualized will calculate and generate only a few dozen DOM tags that are actually in the user's viewport. As you scroll, content and data will be continuously replaced into those available DOM tags, keeping memory at a constant level.
Analyze bundles with Webpack Bundle Analyzer: Find and kill the bad guys
Sử dụng công cụ webpack bundle analyzer giúp bạn trực quan hóa kích thước của Webpack bundle, từ đó dễ dàng phát hiện và loại bỏ các thư viện thừa thãi.
This is my favorite react performance optimization tool. With just one install and run command, you'll see a colorful treemap chart showing exactly which libraries are taking up the most space. Often the culprit for bloating bundle size is importing the entire lodash library instead of individual functions, or using moment.js too heavily. Find them, replace them with lighter solutions, and reconfigure Webpack to remove dead-code.
Diagnostic Tools: Blind Optimization Impossible
To test react app performance accurately, you need to rely on actual metrics from Profiler and measurement tools instead of guessing by feel.
Optimizing without metrics is like traveling at night without lights. You can spend hours fixing a piece of code that isn't actually causing slowness, while bypassing the real bottleneck. Get into the habit of using the professional diagnostic tools below.
React Developer Tools Profiler: Get to the bottom of which components are "doing harm"
The Profiler tab in React Developer Tools allows you to record the rendering process, measure each component's execution time, and pinpoint bottlenecks.
Chỉ cần bật Profiler lên, thực hiện vài thao tác trên UI đang bị lag và nhấn dừng ghi. Bạn sẽ nhận được một biểu đồ ngọn lửa (flamegraph) trực quan. Nó hiển thị rõ component nào render lâu nhất, render mất bao nhiêu mili-giây và nguyên nhân tại sao nó lại bị render lại (do state đổi, hay do hooks thay đổi). Theo dõi sát sao hiệu suất render qua công cụ này giúp bạn khoanh vùng chính xác nơi cần đặt React.memo hoặc useMemo.
Leverage Chrome DevTools Performance: Get an in-depth look at every page activity
Chrome DevTools cung cấp cái nhìn toàn cảnh về call stack, execution time và network, giúp bạn phát hiện các block JavaScript đang chặn main thread.
Since React 19, custom performance tracks have been integrated straight into Chrome DevTools. It allows you to see exactly how much time your component spends on stages like blocking, transitioning or idling. Content download speed also depends a lot on how you get data from the server. Optimizing Fetch API calling REST API in JavaScript helps significantly reduce network latency, thereby making performance graphs smoother.
Core Web Vitals metrics (LCP, FCP, CLS): Understand what users are experiencing
Core Web Vitals là bộ chỉ số của Google đo lường trải nghiệm thực tế, trong đó quan trọng nhất là LCP (tốc độ tải), CLS (độ ổn định giao diện) và INP (độ trễ tương tác).
A smooth React app not only needs high FPS, but also must satisfy Google's strict standards. Below is a summary of the indicators you need to pay attention to:
| Index | Practical meaning | Good |
|---|---|---|
| LCP (Largest Contentful Paint) | Time to complete rendering the largest block of content on the screen. | Under 2.5 seconds |
| CLS (Cumulative Layout Shift) | Measures sudden interface shifts, causing wrong clicks. | Below 0.1 |
| INP / TTI | Page sensitivity when users click or type keys. | Under 200 milliseconds |
(Note: From 2024, INP has officially replaced FID to measure engagement, alongside familiar metrics such as FCP and TTI). To avoid data flow bottlenecks and improve these metrics, mastering Easy-to-understand Async Await Promise JavaScript is a vital skill for every frontend developer.
Take it Further: Less Used But Extremely Effective Techniques
Besides the basic methods, applying debounce, smart local state management and concurrent hooks will increase your application performance.
Once we've taken care of the big bundling and re-rendering issues, it's time to apply micro-optimizations. These small details are what separate an average developer from a true professional.
Smart State Management: When to use Context, when to choose Zustand/Jotai
Tối ưu hóa quản lý state react đòi hỏi bạn phải biết chia nhỏ state; Context API hợp với dữ liệu tĩnh, trong khi Zustand hoặc Jotai giải quyết tốt bài toán re-render cho dữ liệu phức tạp.
Context API rất tốt để truyền theme hay ngôn ngữ, nhưng nếu bạn nhét một object khổng lồ vào đó, bất kỳ thay đổi nhỏ nào cũng làm toàn bộ component tiêu thụ context bị re-render. Giải pháp là sử dụng Zustand hoặc Jotai để component chỉ subscribe chính xác vào phần state mà nó cần. Thói quen sử dụng Immutable data structures cũng giúp React đối chiếu state nhanh hơn.
For large-scale projects, applying Redux Toolkit for modern React state management helps make the data structure transparent, easy to debug and optimize re-render thanks to the selector feature. Furthermore, for the state server, instead of writing the logic to fetch data manually, using React Query TanStack to manage data fetching will completely automate caching, reduce the load on the server and support state management extremely effectively.
Debounce and Throttle: Control dense events
The debounce and throttle techniques help limit the execution frequency of continuous event handling functions such as page scrolling or keystrokes (search input), significantly reducing the load on the main thread.
Imagine a user searches for the keyword "optimize React app performance", if you call the API right after each keystroke, the server will crash and the UI will freeze immediately. The debounce technique will collect all typing attempts and only call the API when the user pauses for about 300ms. Meanwhile, throttle ensures that a function is only allowed to run at most once per certain period of time (for example, updating the scroll bar position every 100ms).
Sử dụng useTransition và useDeferredValue trong React 18
Các hook useTransition và useDeferredValue cho phép React ưu tiên các cập nhật quan trọng (như gõ phím) và trì hoãn các tác vụ nặng (như render danh sách), giữ cho UI luôn phản hồi.
Đây là sức mạnh cốt lõi của Concurrent Rendering. Nếu bạn có một ô input để lọc một danh sách dài hàng ngàn người dùng, việc gõ phím phải được ưu tiên hiển thị ngay lập tức để tạo cảm giác mượt mà. Bằng cách bọc logic lọc danh sách trong useTransition, React sẽ hiểu đó là tác vụ ưu tiên thấp (non-urgent). Nó có thể tạm dừng việc render danh sách để cập nhật ô input trước, giúp giao diện không bao giờ bị "đóng băng" (freeze).
Tối ưu performance cho React app không phải là việc làm một lần rồi thôi, mà là cả một quá trình bảo trì liên tục. Nhưng bạn không cần phải làm mọi thứ cùng lúc. Hãy bắt đầu với việc xác định điểm nghẽn lớn nhất bằng Profiler, tập trung vào việc giảm re-render và tối ưu bundle size. Nắm vững bộ ba memo, useMemo, useCallback và các kỹ thuật code-splitting là bạn đã giải quyết được 80% vấn đề rồi đó. Code mượt, user vui, sếp hài lòng!
Do you have any other cool tricks to optimize React app? Share in the comments so everyone can learn together!
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.