הצגת רשימות היא חלק חשוב בעיצוב של אתר. רשימות מציגות למשל מוצרים, אנשי קשר או כל אוסף אחר. בפרוייקט לדוגמא ראינו הצגה של רשימת רכיבים ושל שלבי ההכנה של המתכון.
כדי שיהיו לי רשימות לעבוד איתן נכנסתי לאתר mockaroo וחוללתי נתונים לדוגמא. את הנתונים העתקתי לקובץ data.json בתיקייה הראשית.
map
כדי להציג רשימה נשתמש בפונקציית map.
import { Text, SafeAreaView, StyleSheet, View } from "react-native";
import userList from '../data.json'
export default function Index() {
return (
<SafeAreaView style={styles.safeContainer}>
{
userList.map(user => {
return (
<View key={user.id}>
<Text>{user.first_name}</Text>
<Text>{user.last_name}</Text>
<Text>{user.email}</Text>
<Text>{user.phone}</Text>
</View>
);
})
}
</SafeAreaView>
);
}
אנחנו מעבירים מפתח עם key={user.id} כדי לאפשר לריאקט לעדכן ביעילות את הרשימה. על מנת לאפשר גלילה נוסיף גם ScrollView.
כל הרשימה מופיעה ביחד, נסדר קצת את העמוד וניצור מסגרת לכל משתמש בנפרד.
import { Text, SafeAreaView, StyleSheet, View, ScrollView } from "react-native";
import userList from '../data.json'
export default function Index() {
return (
<SafeAreaView style={styles.safeContainer}>
<ScrollView style={styles.scrollView}>
{
userList.map(user => {
return (
<View style={styles.card} key={user.id}>
<Text>{user.first_name}</Text>
<Text>{user.last_name}</Text>
<Text>{user.email}</Text>
<Text>{user.phone}</Text>
</View>
);
})
}
</ScrollView>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
safeContainer: {
flex: 1,
backgroundColor: "#f5f5f5",
paddingTop: 25
},
scrollView: {
paddingHorizontal: 16
},
card:{
backgroundColor: "#fff",
padding: 16,
borderRadius: 8,
borderWidth: 1,
marginBottom: 16
}
})

אנחנו רואים שהרשימה מוצגת, אבל יש דרכים טובות יותר להציג רשימה. הבעיה היא שהתצוגה מעבדת את כל הרשימה, גם אם יש 1000 רכיבים, בעוד על המסך אפשר להציג חלק קטן בלבד. למרות שהמשתמש רואה מעט רשומות, הוא יצטרך להמתין שכל הרשימה תטען.
FlatList
הקומפוננטה FlatList טוענת רק את חלקי הרשימה שרואים בתצוגה וכך מונעת זמן טעינה ארוך.
משתנה data מקבל את הרשימה שאותה רוצים להציג. renderItem מחזיר את הקוד שרוצים לבצע עבור כל אובייקט ברשימה.
<FlatList data={userList}
renderItem={({item}) => {
return (
<View style={styles.card} key={item.id}>
<Text>{item.first_name}</Text>
<Text>{item.last_name}</Text>
<Text>{item.email}</Text>
<Text>{item.phone}</Text>
</View>
);
}}
/>
אפשר לטעון את הרשימה גם לרוחב עם הוספת המילה horizontal.
משתנה נוסף הוא keyExtractor שיכול להוציא את המפתח של האובייקט ברשימה או האינדקס שלו.
keyExtractor={(item, index) => item.id.toString()}
Item Separator
Item Separator מייצר מפריד בין האובייקטים ברשימה בלי הראשון והאחרון. בדוגמא הורדתי את המסגרת שמסביב לכל משתמש והוספתי קו מפריד עם שימוש ב-ItemSeparatorComponent.
<FlatList data={userList}
renderItem={({item}) => {
return (
<View key={item.id}>
<Text>{item.first_name}</Text>
<Text>{item.last_name}</Text>
<Text>{item.email}</Text>
<Text>{item.phone}</Text>
</View>
);
}}
keyExtractor={(item, index) => item.id.toString()}
ItemSeparatorComponent={() => {
return (<View style={ styles.separator } />)
}}
/>
...
separator: {
height: 1,
width: '100%',
backgroundColor: '#CCC',
marginTop: 5,
marginBottom: 5
},

List Empty
List Empty מחזיר מה שרוצים אם הרשימה ריקה.
ListEmptyComponent={<Text>No items found</Text>}
List Header and Footer
אפשר להוסיף כותרת ותחתית מותאמים לרשימה.
ListHeaderComponent={<Text style={ styles.usersHeaderText }>Users List</Text>}
ListFooterComponent={<Text style={ styles.usersFooterText }>Click to load more...</Text>}
ה-footer יכול להכיל הערות, דפדוף או דברים אחרים.
SectionList
SectionList מאפשר חלוקה לקטגוריות של המידע. נוסיף למשתמשים שלנו עיר ומקצוע כדי לפלח את המידע.
קודם נהפוך את הרשימה לרשימה שמאגדת את הנתונים לפי עיר.
- נגדיר Item כללי שיקבל את האובייקטים של הרשימה.
- נגדיר פונקציית groupBy שמקבלת רשימה ואת המפתח שליו רוצים לאגד את האובייקטים.
- נקח את הרשימה, נשלח לפונקציה ונקבל רשימה חדשה groupedUsers.
type Item = { [key: string]: any }; // Generic type for any object
const groupBy = (list: Item[], key: string) => {
const groupedData: { [key: string]: Item[] } = {};
list.forEach((item) => {
const groupKey = item[key];
if (!groupedData[groupKey]) {
groupedData[groupKey] = [];
}
groupedData[groupKey].push(item);
});
return Object.keys(groupedData).map((group) => ({
title: group,
data: groupedData[group],
}));
};
const groupedUsers = groupBy(userList, 'city');
נציג א הרשימה, כרגע הוא מוצגת כמו שהוצגה הרשימה הקודמת. עוברים על כל אובייקט ומחזירים את התצוגה שלו. משתמשים בקומפוננטת SectionList על מנת להציג את הרשימה.
<SectionList
sections={groupedUsers}
renderItem={({item}) => {
return (
<View style={styles.card}>
<Text>{item.first_name}</Text>
<Text>{item.last_name}</Text>
</View>
);
}}
/>
כדי לנצל את הוספת ה-sections נוסיף את renderSectionHeader.
<SectionList
sections={groupedUsers}
renderItem={({item}) => {
return (
<View style={styles.card}>
<Text>{item.first_name}</Text>
<Text>{item.last_name}</Text>
</View>
);
}}
renderSectionHeader={({section}) =>
<Text style={styles.sectionHeaderText}>{section.title}</Text>
}
/>
עכשיו המסך נראה כך:

אפשר להשתמש ב-ItemSeparatorComponent וגם ב-SectionSeparatorComponent.