Giới thiệu
Trong React Native, việc quản lý hiệu suất ứng dụng rất quan trọng. Một vấn đề phổ biến là rerender component không cần thiết, dẫn đến hiệu suất kém. Bài viết này sẽ giúp bạn hiểu rõ về rerender và cách tối ưu hóa hiệu suất để cải thiện trải nghiệm người dùng.
1. Rerender Component là gì?
Rerender xảy ra khi một component trong React Native được vẽ lại trên màn hình, dù dữ liệu không thay đổi. Mỗi khi component nhận props hoặc state mới, hàm render sẽ chạy lại. Điều này có thể gây giật lag nếu quá nhiều component bị rerender không cần thiết..
2. Nguyên nhân dẫn đến rerender không cần thiết
- Thay đổi Props: Mỗi khi cha của một component thay đổi props, component con sẽ tự động render lại, ngay cả khi các giá trị props thực tế không thay đổi.
- Thay đổi State: Tương tự như props, mỗi khi state trong component thay đổi, component sẽ tự động rerender. Quản lý state không hiệu quả có thể dẫn đến việc render lại các phần không cần thiết của giao diện.
- Sử dụng
setState
không tối ưu: Việc sử dụngsetState
không đúng cách có thể khiến một component rerender quá nhiều lần, ngay cả khi các giá trị của state không thay đổi. - Không sử dụng React.memo: Nếu một component không được bọc bằng
React.memo
hoặc các phương thức tối ưu hóa khác, nó sẽ luôn được rerender bất kể dữ liệu thực tế có thay đổi hay không.
3. Cách phát hiện rerender không cần thiết
a. React DevTools: React DevTools là một công cụ tuyệt vời để kiểm tra xem component nào đang bị render lại không cần thiết. Bạn có thể xem và theo dõi từng component trong cây component và biết khi nào nó được rerender.
b. React Native Profiler React Native Profiler: là một công cụ tích hợp giúp bạn theo dõi hiệu suất của ứng dụng. Nó cho phép bạn kiểm tra thời gian render của từng component, từ đó phát hiện các đoạn mã gây ra sự giảm hiệu suất.
c. console.log trong hàm render: Một cách đơn giản là thêm console.log
trong hàm render của component để theo dõi xem nó bị rerender bao nhiêu lần.
4. Phương pháp tối ưu hóa hiệu suất
a. Sử dụng React.memo
React.memo
: là một hàm bọc component, chỉ render lại component khi có sự thay đổi thực sự trong props. Điều này giúp ngăn chặn các component con không cần thiết bị render lại.
const MyComponent = React.memo((props) => {
// Component logic
});
b. Sử dụng useCallback
và useMemo
: useCallback
và useMemo
giúp ngăn chặn việc tái tạo lại các hàm hoặc giá trị mỗi khi component cha render.
useCallback
: Giúp bạn ghi nhớ một hàm và chỉ tạo mới khi các dependency thay đổi.useMemo
: Giúp ghi nhớ một giá trị tính toán để tránh tính toán lại ở mỗi lần render.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
const memoizedCallback = useCallback(() => { doSomething(a, b); }, [a, b]);
c. Tránh thay đổi state không cần thiết: Việc thay đổi state không cần thiết sẽ gây ra render lại nhiều component. Hãy chỉ thay đổi state khi thực sự cần thiết và sử dụng setState
một cách cẩn thận.
d. Sử dụng FlatList và SectionList một cách hợp lý: Trong React Native, nếu bạn cần hiển thị danh sách lớn, hãy sử dụng FlatList hoặc SectionList thay vì ScrollView. Các component này được tối ưu hóa để chỉ render những phần tử hiển thị trên màn hình, giúp cải thiện hiệu suất.
e. Lazy loading và Code splitting: Nếu ứng dụng của bạn có nhiều component hoặc chức năng không cần tải ngay lập tức, hãy sử dụng lazy loading và code splitting để giảm tải cho quá trình render ban đầu.
f. Tránh hàm anonymous trong JSX: Hàm anonymous trong JSX (ví dụ trong các sự kiện onPress
, onClick
) có thể dẫn đến việc tạo ra các hàm mới ở mỗi lần render, gây ra rerender không cần thiết.
5. Ví dụ tối ưu hóa hiệu suất trong React Native
Dưới đây là một ví dụ minh họa việc sử dụng React.memo
, useCallback
, và useMemo
để tối ưu hóa hiệu suất của một component:
import React, { useState, useCallback, useMemo } from 'react';
const ChildComponent = React.memo(({ value, onClick }) => {
console.log('ChildComponent render');
return <button onClick={onClick}>{value}</button>;
});
const ParentComponent = () => {
const [count, setCount] = useState(0);
const [text, setText] = useState('');
const increment = useCallback(() => setCount(count + 1), [count]);
const computedValue = useMemo(() => {
return count * 2;
}, [count]);
return (
<div>
<ChildComponent value={computedValue} onClick={increment} />
<input value={text} onChange={(e) => setText(e.target.value)} />
</div>
);
};
export default ParentComponent;
Trong ví dụ trên:
React.memo
được sử dụng để tránh render lạiChildComponent
nếu không có thay đổi thực sự.useCallback
đảm bảo rằng hàmincrement
không bị tái tạo không cần thiết.useMemo
giúp tối ưu hóa việc tính toán giá trịcomputedValue
.
Kết luận
Tối ưu hóa rerender component là một yếu tố quan trọng để đảm bảo hiệu suất mượt mà trong React Native. Bằng cách sử dụng các công cụ như React.memo
, useCallback
, useMemo
và các chiến lược quản lý state hiệu quả, bạn có thể giảm thiểu các lần render không cần thiết, từ đó nâng cao hiệu suất tổng thể của ứng dụng. Hãy luôn kiểm tra và theo dõi hiệu suất ứng dụng để đảm bảo trải nghiệm người dùng tốt nhất.
Tài liệu tham khảo: https://medium.com/@vadim_sotropa/re-rendering-in-react-native-2a5c1748f7f3