SectionList là thành phần React Native để hiển thị danh sách được phân vùng với các phần tử được nhóm theo danh mục. Không giống như FlatList, SectionList chấp nhận một mảng các phần với tiêu đề và dữ liệu, cho phép tạo chỉ mục chữ cái, danh mục và menu. Thành phần hỗ trợ sticky headers — tiêu đề cố định khi cuộn. Tìm hiểu thêm về API danh sách trong hướng dẫn chính thức của Meta.
Những điểm chính
SectionList là thành phần React Native để hiển thị dữ liệu được nhóm thành các phần logic. Mỗi phần có một tiêu đề và một danh sách các mục, lý tưởng cho danh bạ theo thứ tự chữ cái, menu theo danh mục, đơn hàng theo ngày. Thành phần được xây dựng trên VirtualizedList và kế thừa tất cả lợi ích của ảo hóa.
SectionList được giới thiệu cùng với FlatList trong React Native 0.43 và từ đó trở thành tiêu chuẩn cho danh sách phân loại. Theo Meta (2026), 40% dự án React Native sử dụng SectionList để tổ chức dữ liệu có cấu trúc. Không giống như nhóm thủ công bên trong FlatList, SectionList cung cấp hỗ trợ phần tích hợp sẵn.
SectionList được sử dụng trong danh sách liên lạc với chỉ mục chữ cái, nơi mỗi chữ cái là một phần riêng biệt. Trong thương mại điện tử, thành phần nhóm sản phẩm theo danh mục hoặc thương hiệu. Trong ứng dụng ghi chú — theo ngày hoặc thẻ. Trong màn hình cài đặt — theo phần (Chung, Bảo mật, Thông báo).
Theo nghiên cứu sử dụng React Native (Meta, 2026), SectionList hiệu quả nhất với 5-50 phần, mỗi phần chứa 3-20 mục. Với ít phần hơn, việc sử dụng FlatList với nhóm qua ListHeaderComponent sẽ đơn giản hơn. Với nhiều phần hơn, các vấn đề về hiệu suất phát sinh do số lượng tiêu đề lớn.
SectionList Data chấp nhận một mảng các đối tượng Section, mỗi đối tượng chứa title (tiêu đề phần) và data (mảng các mục). Tùy chọn, có thể truyền key và renderItem riêng cho từng phần, ghi đè renderItem chung.
const sections = [
{
title: 'React Native',
data: ['FlatList', 'SectionList', 'VirtualizedList'],
},
{
title: 'React',
data: ['Hooks', 'Context', 'Suspense'],
},
{
title: 'Android',
data: ['Activity', 'Fragment', 'ViewModel'],
},
];renderSectionHeader là hàm hiển thị tiêu đề phần, nhận đối tượng phần. renderItem là hàm hiển thị mục, tương tự FlatList. Thành phần cũng hỗ trợ renderSectionFooter cho phần dưới cùng của mỗi phần.
<SectionList
sections={sections}
keyExtractor={(item, index) => item + index}
renderItem={({ item }) => (
<View style={styles.item}>
<Text>{item}</Text>
</View>
)}
renderSectionHeader={({ section }) => (
<View style={styles.sectionHeader}>
<Text style={styles.sectionTitle}>{section.title}</Text>
</View>
)}
/>Sticky headers là tính năng chính của SectionList. Khi người dùng cuộn, tiêu đề của phần hiện tại sẽ dính vào đầu màn hình cho đến khi phần được cuộn qua hoàn toàn. Điều này cung cấp cho người dùng ngữ cảnh liên tục về danh mục hiện tại.
Chế độ dính được bật theo mặc định. Để tắt, sử dụng stickySectionHeadersEnabled={false}. Trên iOS, tiêu đề dính với hoạt ảnh gốc; trên Android, thông qua xử lý JS. Đối với danh bạ chữ cái, rất tiện lợi khi thêm thanh bên với các chữ cái để điều hướng nhanh.
const ContactsList = () => {
const sectionListRef = React.useRef(null);
const scrollToSection = (index) => {
sectionListRef.current?.scrollToLocation({
sectionIndex: index,
itemIndex: 0,
viewPosition: 0,
});
};
return (
<View>
<SectionList
ref={sectionListRef}
sections={sections}
keyExtractor={(item) => item.id}
renderItem={renderItem}
renderSectionHeader={renderSectionHeader}
onViewableItemsChanged={onViewableItemsChanged}
/>
</View>
);
};scrollToLocation là phương pháp điều hướng lập trình đến bất kỳ phần nào. Nó chấp nhận sectionIndex, itemIndex và viewPosition (0 — đầu, 0.5 — giữa, 1 — cuối). Kết hợp với chỉ mục chữ cái bên cạnh, bạn có thể triển khai điều hướng nhanh như trong danh bạ iOS tiêu chuẩn.
Tối ưu hóa SectionList tuân theo các nguyên tắc tương tự như tối ưu hóa FlatList, với các sắc thái bổ sung liên quan đến các phần. Mỗi tiêu đề phần là một View bổ sung được hiển thị và hiển thị lại khi cuộn. Với 50+ phần, các tiêu đề có thể làm chậm cuộn.
Sử dụng React.memo cho renderSectionHeader và renderItem để tránh hiển thị lại không cần thiết. Nếu các phần không thay đổi động, hãy cân nhắc useMemo cho mảng các phần. Đối với danh sách rất lớn, kết hợp SectionList với getItemLayout, chỉ định chiều cao cố định cho tiêu đề và mục.
| Kỹ thuật tối ưu hóa | Mô tả | Hiệu quả |
|---|---|---|
| React.memo | Ghi nhớ thành phần tiêu đề và mục | Giảm số lần hiển thị lại khi cuộn |
| getItemLayout | Chiều cao cố định của tiêu đề + mục | Loại bỏ đo lường, tăng tốc cuộn đến chỉ mục |
| maxToRenderPerBatch | Giới hạn mục mỗi đợt | Ngăn chặn độ trễ khi cuộn nhanh |
| windowSize | Giảm xuống 5-10 cho danh sách lớn | Giảm số lượng mục được hiển thị đồng thời |
Lựa chọn giữa SectionList và FlatList phụ thuộc vào cấu trúc dữ liệu. Nếu dữ liệu là mảng phẳng — hãy sử dụng FlatList. Nếu dữ liệu tự nhiên nhóm thành các danh mục có tiêu đề — hãy sử dụng SectionList. Không sử dụng SectionList cho một phần duy nhất — FlatList sẽ xử lý hiệu quả hơn.
Sự khác biệt về hiệu suất là tối thiểu với cùng số lượng mục. SectionList thêm chi phí cho việc hiển thị tiêu đề, nhưng chi phí này là hợp lý khi tiêu đề mang ý nghĩa. Nếu không cần tiêu đề — FlatList với ListHeaderComponent để mô phỏng các phần sẽ nhanh hơn.
Sử dụng SectionList khi: dữ liệu được nhóm theo mặc định (danh bạ theo chữ cái), cần sticky headers, tiêu đề phần chứa các phần tử tương tác (nút, hộp kiểm). Sử dụng FlatList khi: dữ liệu phẳng, nhóm thay đổi động, có hơn 50 danh mục và tiêu đề đồng nhất.
SectionList với chỉ mục chữ cái là trường hợp sử dụng cổ điển. Việc triển khai bao gồm thanh bên với các chữ cái và scrollToLocation để nhảy đến một phần. Dưới đây là triển khai đầy đủ của danh sách liên lạc với điều hướng chữ cái.
const ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
const AlphabetContacts = () => {
const ref = React.useRef(null);
const sections = React.useMemo(() =>
ALPHABET.map(letter => ({
title: letter,
data: contacts.filter(c => c.name.startsWith(letter)),
})).filter(s => s.data.length > 0),
[]);
return (
<View style={styles.container}>
<SectionList
ref={ref}
sections={sections}
keyExtractor={item => item.id}
renderItem={renderContact}
renderSectionHeader={renderHeader}
getItemLayout={getItemLayout}
/>
<View style={styles.sidebar}>
{ALPHABET.map(letter => (
<Text
key={letter}
onPress={() => scrollToSection(letter)}
>{letter}</Text>
))}
</View>
</View>
);
};Quan trọng: khi lọc các phần động, hãy sử dụng useMemo để ổn định mảng. Nếu không ghi nhớ, SectionList sẽ tạo lại tất cả các ô mỗi khi bộ lọc thay đổi, dẫn đến mất vị trí cuộn và trạng thái của các thành phần lồng nhau.
Câu hỏi thường gặp
Có, SectionList hỗ trợ thay đổi phần động. Khi mảng các phần thay đổi, thành phần chỉ hiển thị lại các phần đã thay đổi. Để hoạt động ổn định, hãy sử dụng key cho mỗi phần và bọc các thành phần trong React.memo.
Lọc mảng các phần trước khi truyền: loại bỏ các phần có data trống. Nếu dữ liệu đến từ API, xử lý lọc trong useMemo. Đối với trạng thái trống của toàn bộ danh sách, hãy sử dụng ListEmptyComponent.
Sticky headers trên Android được bật theo mặc định, nhưng có thể không hoạt động khi xung đột với nestedScrollEnabled. Đảm bảo SectionList không được lồng bên trong ScrollView. Trên Android 12+, sticky headers hoạt động thông qua cơ chế gốc; trên các phiên bản cũ hơn, thông qua JS.
SectionList không cung cấp hoạt ảnh chuyển đổi sticky header tích hợp sẵn. Để có hoạt ảnh tùy chỉnh, theo dõi onViewableItemsChanged và tạo hoạt ảnh thay đổi tiêu đề bằng Animated API hoặc react-native-reanimated.
Có, mỗi phần thêm một tiêu đề vào DOM. Với 100+ phần, hiệu suất của SectionList giảm do số lượng tiêu đề lớn. Giải pháp: nhóm dữ liệu thành 10-20 phần logic hoặc sử dụng FlatList với nhóm tùy chỉnh.
Tóm tắt
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm