Performance Optimization trong React Js, tăng hiệu suất cực ngon
Trong bài viết này, chúng ta sẽ tìm hiểu về Performance Optimization trong ReactJS và các kỹ thuật tối ưu hiệu suất cần thiết để xây dựng các ứng dụng React đáp ứng được nhu cầu của người dùng.
React JS là một trong những thư viện JavaScript phổ biến nhất và được sử dụng rộng rãi để xây dựng các ứng dụng web hiện đại. Tuy nhiên, khi xây dựng các ứng dụng React lớn và phức tạp, việc tối ưu hiệu suất trở thành một yêu cầu quan trọng để đảm bảo ứng dụng hoạt động mượt mà và đáp ứng tốt nhu cầu của người dùng.
I. Performance Optimization trong React Js là gì?
Performance Optimization trong ReactJS là quá trình tối ưu hiệu suất của ứng dụng ReactJS bằng cách sử dụng các kỹ thuật và công cụ để giảm thiểu số lượng công việc phải thực hiện bởi trình duyệt và máy chủ, giúp cải thiện trải nghiệm người dùng, giảm thời gian tải trang và tăng khả năng mở rộng của ứng dụng.
Có rất nhièu components hỗ trợ các bạn tối ưu hóa ứng dụng. Ví dụ React.memo() sẽ giúp tránh việc render lại các component không sử dụng, PureComponent sẽ kiểm tra có cần render lại một component hay không ...
Bài viết này được đăng tại [free tuts .net]
Như vậy, quá trình sử dụng các phương thức mà react cung cấp này sẽ giúp ứng dụng tối ưu hơn rất nhiều.
II. Các Components trong Performance Optimization
React.memo()
React.memo()
là một component quan trọng trong Performance Optimization của ReactJS. Nó giúp tối ưu hóa hiệu suất bằng cách tránh việc render lại component khi không cần thiết.
Khi sử dụng React.memo(), React sẽ tự động so sánh các props của component trước và sau khi update. Nếu các props không thay đổi, React sẽ bỏ qua việc render lại component, giúp giảm thiểu số lần render và cải thiện hiệu suất ứng dụng.
React.memo()
được sử dụng như một HOC (Higher-Order Component) và bao bọc bên ngoài component cần được tối ưu hóa.
Ví dụ:
import React, { memo } from 'react'; const MyComponent = memo((props) => { // Component code here });
Lưu ý rằng React.memo()
chỉ hoạt động với các component dựa trên props và không hoạt động với các component sử dụng state hoặc context. Nếu muốn tối ưu hóa các component sử dụng state hoặc context, có thể sử dụng PureComponent hoặc shouldComponentUpdate()
thay thế.
PureComponent
Trong React, một PureComponent
là một lớp component được cung cấp sẵn mà tự động thực hiện các kiểm tra sâu (deep checks) để xác định xem có cần render lại component hay không. Khi một component được render lại, nó sẽ tạo ra một cây DOM mới và tất cả các thành phần (components) bên trong của nó cũng sẽ được render lại. Việc render lại có thể làm giảm hiệu suất của ứng dụng.
Tuy nhiên, nếu chỉ có những thay đổi nhỏ trong component, việc render lại là không cần thiết.PureComponent
tự động thực hiện các kiểm tra để xác định xem props và state của component đã thay đổi hay chưa. Nếu không có sự thay đổi nào, PureComponent
sẽ không render lại component, giúp cải thiện hiệu suất của ứng dụng.
Một ví dụ về sử dụng PureComponent
trong React là trong một ứng dụng web, ta có một component hiển thị danh sách các sản phẩm và component này được cập nhật mỗi khi có một sản phẩm mới được thêm vào hoặc một sản phẩm đã có được cập nhật.
Khi sử dụng PureComponent
, ta có thể viết component hiển thị danh sách sản phẩm này như sau:
Ví Dụ:
import React, { PureComponent } from 'react'; class ProductList extends PureComponent { render() { const { products } = this.props; return ( <ul> {products.map(product => ( <li key={product.id}>{product.name}</li> ))} </ul> ); } }
Trong ví dụ này, ta sử dụng PureComponent
để đảm bảo rằng component chỉ được render lại khi có sự thay đổi trong products. Nếu không có sự thay đổi, PureComponent
sẽ không thực hiện việc render lại component, giúp tăng hiệu suất của ứng dụng.
Với mỗi lần cập nhật danh sách sản phẩm, React sẽ tự động kiểm tra sâu (deep check) để xác định xem danh sách sản phẩm có thay đổi hay không. Nếu danh sách không thay đổi, component sẽ không được render lại, giúp tiết kiệm tài nguyên và tăng tốc độ hiển thị trang web.
Tuy nhiên, nếu trong component này có nhiều props và state phức tạp khác, việc sử dụng PureComponent
có thể không phù hợp và ta nên sử dụng các kỹ thuật tối ưu hơn để cải thiện hiệu suất
shouldComponentUpdate()
Trong React, shouldComponentUpdate()
là một lifecycle method được gọi trước khi một component được render lại. Phương thức này cho phép ta kiểm soát việc render lại component bằng cách xác định xem component có cần được render lại hay không dựa trên những thay đổi trong props hoặc state.
Nếu shouldComponentUpdate()
trả về false, component sẽ không được render lại. Nếu phương thức này trả về true, component sẽ được render lại. Việc sử dụng shouldComponentUpdate()
có thể giúp tối ưu hóa hiệu suất của ứng dụng bằng cách tránh render lại component khi không cần thiết.
Tuy nhiên, việc sử dụng shouldComponentUpdate()
có thể làm cho mã của component trở nên phức tạp và khó hiểu hơn. Ngoài ra, việc thực hiện các kiểm tra tùy chỉnh trong phương thức này cũng có thể làm giảm hiệu suất của ứng dụng nếu không được sử dụng đúng cách.
Ví dụ dưới đây cho thấy cách sử dụng shouldComponentUpdate()
để kiểm soát việc render lại component:
import React, { Component } from 'react'; class MyComponent extends Component { shouldComponentUpdate(nextProps, nextState) { // Kiểm tra xem có sự thay đổi trong props hoặc state không if (this.props.foo === nextProps.foo && this.state.bar === nextState.bar) { return false; // Không cần render lại component } return true; // Cần render lại component } render() { return ( <div> // Nội dung component </div> ); } }
Trong ví dụ này, ta sử dụng shouldComponentUpdate()
để kiểm tra xem có sự thay đổi trong props (this.props.foo
và nextProps.foo
) và state (this.state.bar
và nextState.bar
) của component không. Nếu không có sự thay đổi, ta trả về false để ngăn component được render lại.
Tóm lại, shouldComponentUpdate()
là một trong những cách để tối ưu hóa hiệu suất của ứng dụng React bằng cách kiểm soát việc render lại component. Tuy nhiên, cần cân nhắc khi sử dụng để đảm bảo tính hiệu quả và độ tin cậy của ứng dụng.
React.lazy()
React.lazy()
là một API mới được giới thiệu trong React 16.6.0, cho phép tạo các lazy-loaded
components, tức là chỉ tải các components cần thiết khi cần sử dụng, chứ không tải tất cả các components cùng lúc. Điều này giúp cải thiện hiệu suất của ứng dụng bằng cách giảm thời gian tải các components không cần thiết và giảm kích thước của bundle.
Khi sử dụng React.lazy()
, ta có thể định nghĩa một component dưới dạng hàm import() trả về một promise. Khi component này được sử dụng, React sẽ tự động tải và render component đó.
Ví dụ sau đây minh họa cách sử dụng React.lazy()
để lazy load một component:
import React, { lazy, Suspense } from 'react'; const MyComponent = lazy(() => import('./MyComponent')); function App() { return ( <div> <Suspense fallback={<div>Loading...</div>}> <MyComponent /> </Suspense> </div> ); }
Trong ví dụ này, ta sử dụng lazy()
để định nghĩa MyComponent dưới dạng một hàm import(). Sau đó, ta sử dụng component <Suspense>
để hiển thị một placeholder (<div>Loading...</div>
) trong khi component đang được tải. Khi component được tải xong, React sẽ tự động render component đó.
Tuy nhiên, khi sử dụng React.lazy()
, cần cân nhắc khi áp dụng cho các trường hợp phù hợp, chẳng hạn như các components lớn, phức tạp hoặc không được sử dụng thường xuyên. Việc sử dụng quá nhiều lazy-loaded
components có thể dẫn đến tăng thời gian phản hồi của ứng dụng do tải các components khi cần thiết.
Tóm lại, React.lazy()
là một cách để cải thiện hiệu suất của ứng dụng React bằng cách giảm thời gian tải và kích thước của bundle bằng cách tải các components cần thiết khi cần sử dụng. Tuy nhiên, cần cân nhắc khi sử dụng để đảm bảo tính hiệu quả và độ tin cậy của ứng dụng.
useCallback()
useCallback()
là một hook trong React được sử dụng để tối ưu hóa hiệu suất của ứng dụng bằng cách giảm số lần render của các components.
Khi một component được render, các hàm và các object literals bên trong component đó sẽ được tạo mới. Việc tạo mới này có thể gây ra việc render lại các components con, dù chúng không thay đổi props. Điều này có thể làm chậm tốc độ của ứng dụng, đặc biệt là khi các components con có kích thước lớn.
Với useCallback()
, ta có thể tạo ra một hàm mới chỉ khi các dependencies của nó thay đổi. Điều này giúp giảm số lần render của các components, vì các hàm được tạo lại chỉ khi các dependencies của chúng thay đổi.
Ví dụ sau đây minh họa cách sử dụng useCallback()
:
import React, { useState, useCallback } from 'react'; function MyComponent(props) { const [count, setCount] = useState(0); const handleClick = useCallback(() => { setCount(count + 1); }, [count]); return ( <div> <p>Count: {count}</p> <button onClick={handleClick}>Increment Count</button> </div> ); }
Trong ví dụ này, ta sử dụng useCallback()
để tạo hàm handleClick
. Hàm này chỉ được tạo lại khi dependency count thay đổi. Trong trường hợp này, nếu count không thay đổi, hàm handleClick
sẽ không được tạo lại. Việc này giúp giảm số lần render của component MyComponent.
Tuy nhiên, cần cân nhắc khi sử dụng useCallback()
vì việc sử dụng quá nhiều có thể dẫn đến tình trạng lãng phí bộ nhớ hoặc làm tăng thời gian phản hồi của ứng dụng.
Tóm lại, useCallback()
là một cách để tối ưu hóa hiệu suất của ứng dụng React bằng cách giảm số lần render của các components. Việc sử dụng hook này phù hợp trong trường hợp các components con có kích thước lớn và cần render lại nhiều lần.
useMemo()
useMemo()
là một hook trong React được sử dụng để tối ưu hóa hiệu suất của ứng dụng bằng cách cache giá trị tính toán và trả về giá trị đã được cache khi các dependency không thay đổi. Điều này giúp giảm số lần tính toán lại, đặc biệt là khi tính toán phức tạp.
Ví dụ sau đây minh họa cách sử dụng useMemo()
để tính toán giá trị của một biến result:
import React, { useMemo } from 'react'; function MyComponent(props) { const [number1, setNumber1] = useState(0); const [number2, setNumber2] = useState(0); const result = useMemo(() => { console.log('compute result'); return number1 + number2; }, [number1, number2]); return ( <div> <p>Number 1: {number1}</p> <input value={number1} onChange={(e) => setNumber1(parseInt(e.target.value))} /> <p>Number 2: {number2}</p> <input value={number2} onChange={(e) => setNumber2(parseInt(e.target.value))} /> <p>Result: {result}</p> </div> ); }
Trong ví dụ này, ta sử dụng useMemo()
để tính toán giá trị của biến result dựa trên number1 và number2. Giá trị của result sẽ được tính toán lại chỉ khi các dependency của nó (trong trường hợp này là number1 và number2) thay đổi. Nếu các dependency không thay đổi, useMemo()
sẽ trả về giá trị đã được cache của result, giúp giảm số lần tính toán lại và tăng tốc độ của ứng dụng.
Tuy nhiên, cần cân nhắc khi sử dụng useMemo()
vì việc sử dụng quá nhiều có thể dẫn đến tình trạng lãng phí bộ nhớ hoặc làm tăng thời gian phản hồi của ứng dụng. useMemo()
là một cách để tối ưu hóa hiệu suất của ứng dụng React bằng cách cache giá trị tính toán và trả về giá trị đã được cache khi các dependency không thay đổi. Việc sử dụng hook này phù hợp trong trường hợp tính toán phức tạp và cần giảm số lần tính toán lại.
Top 3 câu hỏi hay nhất về Performance Optimization
1.Để hiểu hơn về cách sử dụng PureComponent trong React để cải thiện hiệu suất ứng dụng
Link bài viết: http://viblo.asia/p/tip-de-cai-thien-hieu-suat-cua-ung-dung-react-RnB5pyqYKPG
2. Khi nào nên sử dụng useMemo và useCallback trong React
Link bài viết: https://topdev.vn/blog/khi-nao-nen-su-dung-usememo-va-usecallback-trong-react/
3. Làm thế nào để tối ưu hoá ứng dụng React với Lazy Loading
Link bài viết: https://viblo.asia/p/toi-uu-hoa-ung-dung-react-voi-lazy-loading-YWOZr83w5Q0
Kết Luận
Việc tối ưu hiệu suất ứng dụng React là cần cân bằng giữa độ phức tạp và hiệu suất. Tối ưu hóa hiệu suất không phải là mục đích cuối cùng mà nó là một công cụ để cải thiện trải nghiệm người dùng. Việc tối ưu hóa hiệu suất có thể giúp tăng tốc độ ứng dụng, giảm thời gian phản hồi và tăng trải nghiệm người dùng.
Để tối ưu hiệu suất, có nhiều kỹ thuật và công cụ có thể sử dụng, chẳng hạn như sử dụng PureComponent
, sử dụng shouldComponentUpdate
, sử dụng React.lazy
để tải chậm các component, sử dụng useCallback
và useMemo
để tránh tính toán lại nhiều lần và sử dụng thư viện React Profiler để phân tích hiệu suất của ứng dụng.
Tuy nhiên, việc tối ưu hóa hiệu suất cũng có thể gây ra những vấn đề khác, chẳng hạn như mã nguồn phức tạp hơn hoặc khó bảo trì hơn. Do đó, cần cân nhắc và lựa chọn các kỹ thuật và công cụ tối ưu hóa hiệu suất phù hợp để đạt được mục đích cải thiện trải nghiệm người dùng mà không ảnh hưởng đến tính linh hoạt và bảo trì của ứng dụng.