SectionList — компонент React Native для відображення секціонованих списків із групуванням елементів за категоріями. На відміну від FlatList, SectionList приймає масив секцій із заголовками та даними, що дозволяє створювати алфавітні покажчики, каталоги та меню. Компонент підтримує sticky headers — закріплені заголовки під час скролу. Докладніше про API списків читайте в офіційному посібнику Meta.
Головне
SectionList — компонент React Native для відображення даних, згрупованих у логічні секції. Кожна секція має заголовок і список елементів, що ідеально підходить для контактів за абеткою, меню за категоріями, замовлень за датами. Компонент побудовано на VirtualizedList, і він успадковує всі переваги віртуалізації.
SectionList з'явився разом із FlatList у React Native 0.43 і відтоді є стандартом для категорізованих списків. За даними Meta (2026), 40% проєктів на React Native використовують SectionList для організації структурованих даних. На відміну від ручного групування всередині FlatList, SectionList надає вбудовану підтримку секцій.
SectionList застосовується в контакт-листах з алфавітним покажчиком, де кожна літера — окрема секція. В електронній комерції компонент групує товари за категоріями або брендами. У додатках для нотаток — за датами або тегами. У налаштуваннях — за розділами (Основні, Безпека, Сповіщення).
За даними дослідження використання React Native (Meta, 2026), SectionList найефективніший при 5-50 секціях із 3-20 елементами в кожній. За меншої кількості секцій простіше використовувати FlatList із групуванням через ListHeaderComponent. За більшої кількості секцій виникають проблеми з продуктивністю через велику кількість заголовків.
SectionList Data приймає масив об'єктів Section, кожен із яких містить title (заголовок секції) та data (масив елементів). Додатково можна передавати key та renderItem для кожної секції окремо, перевизначаючи загальний renderItem.
const sections = [
{
title: 'React Native',
data: ['FlatList', 'SectionList', 'VirtualizedList'],
},
{
title: 'React',
data: ['Hooks', 'Context', 'Suspense'],
},
{
title: 'Android',
data: ['Activity', 'Fragment', 'ViewModel'],
},
];renderSectionHeader — функція рендерингу заголовка секції, що отримує об'єкт секції. renderItem — функція рендерингу елемента, аналогічна FlatList. Компонент також підтримує renderSectionFooter для нижньої частини кожної секції.
<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 — ключова особливість SectionList. Коли користувач скролить, заголовок поточної секції прилипає до верхнього краю екрана, поки секція повністю не проскролиться. Це дає користувачеві постійний контекст про поточну категорію.
Режим sticky увімкнено за замовчуванням. Для вимкнення використовуйте stickySectionHeadersEnabled={false}. На iOS заголовки прилипають із нативною анімацією, на Android — через JS-обробку. Для алфавітних довідників зручно додати бічну панель із літерами для швидкої навігації.
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 — метод для програмної навігації до будь-якої секції. Приймає sectionIndex, itemIndex та viewPosition (0 — початок, 0.5 — центр, 1 — кінець). Комбінуючи з бічним алфавітним індексом, можна реалізувати швидку навігацію як у стандартних контактах iOS.
Оптимізація SectionList слідує тим самим принципам, що й оптимізація FlatList, із додатковими нюансами, пов'язаними із секціями. Кожен заголовок секції — додатковий View, який рендериться та перерендериться під час скролу. При 50+ секціях заголовки можуть уповільнити скрол.
Використовуйте React.memo для renderSectionHeader та renderItem, щоб уникнути зайвих перерендерів. Якщо секції не змінюються динамічно, розгляньте useMemo для масиву секцій. Для дуже великих списків комбінуйте SectionList із getItemLayout, вказуючи фіксовану висоту заголовків та елементів.
| Прийом оптимізації | Опис | Ефект |
|---|---|---|
| React.memo | Мемоізація компонентів заголовків та елементів | Знижує кількість перерендерів під час скролу |
| getItemLayout | Фіксована висота заголовка + елемента | Прибирає вимірювання, прискорює скрол до індексу |
| maxToRenderPerBatch | Обмеження елементів у батчі | Запобігає затримкам при швидкому скролі |
| windowSize | Зменшення до 5-10 для великих списків | Знижує кількість одночасно зареєстрованих елементів |
Вибір між SectionList та FlatList залежить від структури даних. Якщо дані є плоским масивом — використовуйте FlatList. Якщо дані природно групуються в категорії із заголовками — SectionList. Не використовуйте SectionList для однієї секції — FlatList впорається ефективніше.
Різниця в продуктивності мінімальна за однакової кількості елементів. SectionList додає навантаження на рендеринг заголовків, але це навантаження виправдане, коли заголовки несуть смислове навантаження. Якщо заголовки не потрібні — FlatList із ListHeaderComponent для імітації секцій буде швидшим.
Використовуйте SectionList, коли: дані згруповані за замовчуванням (контакти за літерами), потрібні sticky headers, заголовки секцій містять інтерактивні елементи (кнопки, прапорці). Використовуйте FlatList, коли: дані плоскі, групування змінюється динамічно, категорій більше 50 і заголовки однотипні.
SectionList з алфавітним покажчиком — класичний приклад використання. Реалізація включає бічну панель із літерами та scrollToLocation для стрибка до секції. Нижче — повна реалізація контакт-листа з алфавітною навігацією.
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>
);
};Важливо: при динамічній фільтрації секцій використовуйте useMemo для стабілізації масиву. Без мемоізації SectionList буде перестворювати всі комірки при кожній зміні фільтра, що призведе до втрати скролу та стану вкладених компонентів.
Часті запитання
Так, SectionList підтримує динамічну зміну секцій. При зміні масиву секцій компонент перерендерить лише змінені секції. Для стабільної роботи використовуйте key для кожної секції та обгортайте компоненти в React.memo.
Фільтруйте масив секцій перед передачею: видаліть секції з порожнім data. Якщо дані надходять із API, обробляйте фільтрацію в useMemo. Для порожнього стану всього списку використовуйте ListEmptyComponent.
Sticky headers на Android увімкнені за замовчуванням, але можуть не працювати при конфлікті з nestedScrollEnabled. Переконайтеся, що SectionList не вкладено в ScrollView. На Android 12+ sticky headers працюють через нативний механізм, на старих версіях — через JS.
SectionList не надає вбудованої анімації зміни sticky header. Для кастомної анімації відстежуйте onViewableItemsChanged та анімуйте зміну заголовка через Animated API або react-native-reanimated.
Так, кожна секція додає заголовок у DOM. При 100+ секціях продуктивність SectionList падає через велику кількість заголовків. Рішення: згрупуйте дані в 10-20 логічних секцій або використовуйте FlatList із кастомним групуванням.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.