การแสดงรายการข้อมูลด้วย FlatList
สวัสดีครับเพื่อนๆ นักพัฒนา React Native ทุกท่าน! จากบทที่แล้วที่เราได้เรียนรู้เกี่ยวกับการสร้างปุ่มกดด้วย Button และ TouchableOpacity กันไปแล้ว ในบทนี้เราจะมาเรียนรู้วิธีการแสดงรายการข้อมูลจำนวนมากอย่างมีประสิทธิภาพด้วย FlatList ซึ่งเป็น Component ที่ขาดไม่ได้ในการสร้างแอปพลิเคชันที่มีข้อมูลเยอะๆ ครับ
ทำไมต้อง FlatList?
ลองนึกภาพว่าเราต้องการแสดงรายชื่อเพื่อน 100 คนในแอปของเรา หากเราใช้ View และ Text มาเรียงต่อกัน 100 อัน อาจจะทำให้แอปของเราหน่วงหรือกระตุกได้ เพราะการสร้าง Component จำนวนมากพร้อมกัน จะกินทรัพยากรเครื่องเยอะมาก FlatList ถูกออกแบบมาเพื่อแก้ปัญหานี้โดยเฉพาะ โดยจะทำการ Render เฉพาะ Component ที่มองเห็นบนหน้าจอเท่านั้น (Virtualization) ทำให้แอปของเราทำงานได้อย่างลื่นไหล แม้จะมีข้อมูลจำนวนมหาศาล
การใช้งาน FlatList เบื้องต้น
FlatList เป็น Component ที่รับ Props หลักๆ 2 ตัว คือ data และ renderItem
data: คือ Array ของข้อมูลที่เราต้องการแสดงrenderItem: คือ Function ที่รับข้อมูลแต่ละตัวในdataมา Render เป็น Component
มาดูตัวอย่างโค้ดกันเลยครับ
import React from 'react';
import { FlatList, StyleSheet, Text, View } from 'react-native';
const data = [
{ id: '1', name: 'John Doe' },
{ id: '2', name: 'Jane Smith' },
{ id: '3', name: 'Peter Jones' },
{ id: '4', name: 'Mary Brown' },
];
const Item = ({ name }) => (
<View style={styles.item}>
<Text style={styles.title}>{name}</Text>
</View>
);
const App = () => {
const renderItem = ({ item }) => (
<Item name={item.name} />
);
return (
<View style={styles.container}>
<FlatList
data={data}
renderItem={renderItem}
keyExtractor={item => item.id}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: 20,
},
item: {
backgroundColor: '#f9c2ff',
padding: 20,
marginVertical: 8,
marginHorizontal: 16,
},
title: {
fontSize: 32,
},
});
export default App;
คำอธิบายโค้ด:
- เรา import
FlatList,StyleSheet,TextและViewจากreact-native - สร้าง Array ชื่อ
dataเก็บข้อมูลชื่อและ ID ของคน - สร้าง Component ชื่อ
Itemเพื่อแสดงข้อมูลแต่ละคน โดยรับnameเป็น Prop - สร้าง Function ชื่อ
renderItemที่รับitem(ข้อมูลแต่ละตัวในdata) และส่งitem.nameให้กับ ComponentItem - ใน Component
Appเราใช้FlatListโดยกำหนดdataเป็น Arraydataของเรา และrenderItemเป็น FunctionrenderItem keyExtractorคือ Prop ที่จำเป็นต้องกำหนด เพื่อให้FlatListรู้ว่า Key ไหนคือ Unique Key ของแต่ละ Item ใน List เราใช้item.idเพราะเรากำหนดให้เป็น Unique ID- เราสร้าง
StyleSheetเพื่อตกแต่ง Component ให้สวยงาม
การปรับแต่ง FlatList
FlatList มี Props อีกมากมายที่เราสามารถใช้ปรับแต่งได้ เช่น
horizontal: กำหนดให้แสดงรายการในแนวนอนnumColumns: กำหนดจำนวน Column ในแนวตั้ง (ใช้ได้เฉพาะเมื่อไม่ได้กำหนดhorizontal)ListHeaderComponent: Component ที่จะแสดงเป็น Header ของ ListListFooterComponent: Component ที่จะแสดงเป็น Footer ของ ListItemSeparatorComponent: Component ที่จะแสดงคั่นระหว่างแต่ละ ItemonEndReached: Function ที่จะถูกเรียกเมื่อเลื่อนลงไปถึงท้าย ListonEndReachedThreshold: กำหนดระยะห่างจากท้าย List (เป็นสัดส่วน 0-1) ที่จะให้เรียกonEndReachedrefreshing: กำหนดว่ากำลัง Refresh ข้อมูลอยู่หรือไม่onRefresh: Function ที่จะถูกเรียกเมื่อทำการ Refresh ข้อมูล
มาดูตัวอย่างการใช้งาน Props เหล่านี้กันครับ
import React, { useState } from 'react';
import { FlatList, StyleSheet, Text, View, ActivityIndicator, RefreshControl } from 'react-native';
const data = [
{ id: '1', name: 'John Doe' },
{ id: '2', name: 'Jane Smith' },
{ id: '3', name: 'Peter Jones' },
{ id: '4', name: 'Mary Brown' },
{ id: '5', name: 'David Lee' },
{ id: '6', name: 'Sarah Wilson' },
{ id: '7', name: 'Michael Garcia' },
{ id: '8', name: 'Linda Rodriguez' },
{ id: '9', name: 'Christopher Williams' },
{ id: '10', name: 'Angela Davis' },
];
const Item = ({ name }) => (
<View style={styles.item}>
<Text style={styles.title}>{name}</Text>
</View>
);
const App = () => {
const [refreshing, setRefreshing] = useState(false);
const [loadingMore, setLoadingMore] = useState(false);
const [listData, setListData] = useState(data.slice(0,5)); // แสดงข้อมูลแค่ 5 รายการแรก
const renderItem = ({ item }) => (
<Item name={item.name} />
);
const onRefresh = () => {
setRefreshing(true);
// จำลองการดึงข้อมูลใหม่
setTimeout(() => {
setListData(data); // โหลดข้อมูลทั้งหมด
setRefreshing(false);
}, 2000);
};
const loadMoreData = () => {
if (loadingMore) return; // ป้องกันการโหลดซ้ำ
setLoadingMore(true);
// จำลองการดึงข้อมูลเพิ่มเติม
setTimeout(() => {
const nextData = data.slice(listData.length, listData.length + 5);
setListData([...listData, ...nextData]);
setLoadingMore(false);
}, 1000);
};
const renderFooter = () => {
return (
loadingMore ? (
<View style={{ paddingVertical: 20 }}>
<ActivityIndicator size="large" color="#0000ff" />
</View>
) : null
);
};
return (
<View style={styles.container}>
<FlatList
data={listData}
renderItem={renderItem}
keyExtractor={item => item.id}
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
}
ListFooterComponent={renderFooter}
onEndReached={loadMoreData}
onEndReachedThreshold={0.5}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: 20,
},
item: {
backgroundColor: '#f9c2ff',
padding: 20,
marginVertical: 8,
marginHorizontal: 16,
},
title: {
fontSize: 32,
},
});
export default App;
คำอธิบายโค้ดเพิ่มเติม:
- เราเพิ่ม
useStateHook เพื่อจัดการ State ของrefreshingและloadingMore - เราใช้
RefreshControlเพื่อเพิ่ม Pull-to-Refresh Functionality onRefreshจะถูกเรียกเมื่อผู้ใช้ทำการ Pull-to-Refresh เราจำลองการดึงข้อมูลใหม่โดยใช้setTimeout- เราใช้
ListFooterComponentเพื่อแสดงActivityIndicator(ตัว Loading) เมื่อกำลังโหลดข้อมูลเพิ่มเติม onEndReachedจะถูกเรียกเมื่อเลื่อนลงไปใกล้ถึงท้าย List เราจำลองการดึงข้อมูลเพิ่มเติมโดยใช้setTimeoutonEndReachedThresholdกำหนดไว้ที่ 0.5 หมายความว่าonEndReachedจะถูกเรียกเมื่อเลื่อนลงไปถึงครึ่งทางของ Item สุดท้าย
ข้อผิดพลาดที่พบบ่อยและวิธีแก้ไข
Warning: Each child in a list should have a unique "key" prop.: เกิดจากการที่เราไม่ได้กำหนดkeyExtractorหรือกำหนด Key ที่ไม่ Unique ให้กับแต่ละ Item ใน List วิธีแก้ไขคือ กำหนดkeyExtractorให้ถูกต้อง โดยใช้ Unique ID ของแต่ละ Item- Performance issues when rendering large lists: เกิดจากการที่เรา Render Component ที่ซับซ้อนมากเกินไปใน
renderItemวิธีแก้ไขคือ พยายามทำให้ Component ที่ Render ในrenderItemมีขนาดเล็กและเรียบง่ายที่สุดเท่าที่จะทำได้ หรือใช้React.memoเพื่อป้องกันการ Render Component ที่ไม่จำเป็น - FlatList not rendering: ตรวจสอบให้แน่ใจว่า
dataเป็น Array ที่ถูกต้อง และrenderItemทำงานได้อย่างถูกต้อง นอกจากนี้ ตรวจสอบ Style ของ Container ว่ามี Height เพียงพอหรือไม่
สรุป
ในบทนี้เราได้เรียนรู้เกี่ยวกับการใช้งาน FlatList เพื่อแสดงรายการข้อมูลจำนวนมากอย่างมีประสิทธิภาพ เราได้เรียนรู้การกำหนด data และ renderItem และการปรับแต่ง FlatList ด้วย Props ต่างๆ หวังว่าเพื่อนๆ จะสามารถนำความรู้ที่ได้จากบทนี้ไปประยุกต์ใช้ในการสร้างแอปพลิเคชันของตัวเองได้นะครับ
ในบทต่อไป เราจะมาเรียนรู้เกี่ยวกับการ Navigation หรือการเปลี่ยนหน้าในแอปพลิเคชันกันครับ เตรียมตัวให้พร้อม แล้วเจอกันในบทหน้าครับ!