Trong quá trình phát triển ứng dụng web hiện đại, hiệu suất là một trong những yếu tố then chốt quyết định sự thành công. Đối với các ứng dụng được xây dựng bằng React, việc tối ưu hiệu suất đóng vai trò vô cùng quan trọng. Một trong những yếu tố ảnh hưởng trực tiếp đến hiệu suất của ứng dụng React chính là việc render lại component không cần thiết.
Để hiểu rõ hơn về vấn đề này, hãy cùng phân tích một số sai lầm phổ biến mà lập trình viên React thường mắc phải, đồng thời tìm hiểu cách khắc phục hiệu quả.
1. Tránh lạm dụng hàm inline quá nhiều
Đầu tiên, việc lạm dụng hàm inline trong JSX có thể dẫn đến render lại không mong muốn. Lý do là bởi React coi mỗi hàm mới được tạo ra là một prop mới trên mỗi lần render.
Sau đây là ví dụ minh họa cho việc sử dụng không đúng cách:
function ButtonComponent() { return <button onClick={() => handleClick()}>Click me</button>;
}
Điều này sẽ khiến cho hàm handleClick được tạo ra liên tục mỗi lần kết xuất, dẫn tới dư thừa không cần thiết. Để giải quyết vấn đề này, chúng ta có thể sử dụng useCallback - một hook cho phép ghi nhớ hàm handleClick và ngăn chặn việc tạo lại hàm trên mỗi lần render.
import { useCallback } from 'react'; function ButtonComponent() { const handleClick = useCallback(() => { // Handle click logic }, []); return <button onClick={handleClick}>Click me</button>;
}
2. Sử dụng không đúng cách React.memo
Một sai lầm phổ biến khác là việc sử dụng không đúng cách React.memo. Mặc dù memoization giúp bỏ qua render lại khi props của component không thay đổi, nhưng việc không triển khai hàm so sánh tùy chỉnh có thể dẫn đến sử dụng sai React.memo.
const MemoizedComponent = React.memo(MyComponent);
Để sử dụng React.memo một cách chính xác, bạn nên dùng hàm so sánh tùy chỉnh để chỉ kích hoạt render lại khi prop itemId thay đổi. Cuối cùng, đối với các component dạng class không mở rộng PureComponent, việc triển khai shouldComponentUpdate một cách thủ công cho phép kiểm soát chi tiết hơn về thời điểm component render lại.
const MemoizedComponent = React.memo(MyComponent, (prevProps, nextProps) => { return prevProps.itemId === nextProps.itemId;
});
3. Sử dụng React.Component
Khi làm việc với component dạng class, sử dụng React.PureComponent là một lựa chọn tối ưu. React.PureComponent đảm bảo rằng component chỉ render lại khi props hoặc state thay đổi. Ngược lại, sử dụng React.Component có thể dẫn đến render lại không cần thiết.
class CardComponent extends React.Component { // Component logic
}
Như trường hợp ở trên sẽ không hề tối ưu so với trường hợp phía dưới đây:
class CardComponent extends React.PureComponent { // Component logic
}
Bằng cách mở rộng React.PureComponent, React sẽ so sánh các prop và state một cách hời hợt, tránh việc render lại không cần thiết.
4. Tối ưu không đúng cách useSelector
Việc tối ưu useSelector trong Functional Component cũng là một yếu tố đáng lưu ý. Khi sử dụng useSelector từ react-redux, việc chỉ chọn phần state cần thiết là rất quan trọng, tránh trường hợp component re-render mỗi khi bất kỳ phần nào của state thay đổi.
import { useSelector } from 'react-redux'; const DataComponent = () => { const globalState = useSelector((state) => state); // Render logic
};
Trường hợp bên trên sử dụng không đúng cách useSelector, gây lãng phí tài nguyên, bạn có thể sửa lại như sau:
import { useSelector } from 'react-redux'; const DataComponent = () => { const selectedData = useSelector((state) => state.specificSlice); // Render logic based on specific slice
};
Bằng cách chỉ chọn phần cần thiết của trạng thái, bạn sẽ giảm thiểu việc kết xuất lại.
5. Triển khai shouldComponentUpdatetrong các thành phần lớp
Cuối cùng, đối với các component dạng class không mở rộng PureComponent, việc triển khai shouldComponentUpdate một cách thủ công cho phép kiểm soát chi tiết hơn về thời điểm component render lại.
class ListItem extends React.Component { // Component logic
}
Bằng cách tùy chỉnh shouldComponentUpdate, chúng ta có thể đảm bảo rằng component chỉ render lại khi prop itemId hoặc state value thay đổi, tránh việc render lại mỗi khi component cha render.
class ListItem extends React.Component { shouldComponentUpdate(nextProps, nextState) { return this.props.itemId !== nextProps.itemId || this.state.value !== nextState.value; } // Component logic
}
Tóm lại, bằng cách áp dụng những kỹ thuật được đề cập trong bài viết, bạn có thể giảm thiểu đáng kể việc render lại không cần thiết trong ứng dụng React của mình. Từ đó, ứng dụng của bạn sẽ hoạt động mượt mà và hiệu quả hơn. Việc hiểu rõ khi nào và làm thế nào để tối ưu hóa quá trình render có thể cải thiện đáng kể trải nghiệm người dùng bằng cách cung cấp các ứng dụng nhanh hơn và phản hồi nhanh hơn. Cảm ơn các bạn đã theo dõi.