- vừa được xem lúc

Sử dụng Load More và Refresh với Flatlist React native

0 0 4

Người đăng: Sang Pham

Theo Viblo Asia

Trong bài viết này, mình sẽ chia sẻ hai tính năng là "Load More" và "Refresh" trong Flatlist. Load More cho phép người dùng tải thêm dữ liệu khi người dùng cuộn xuống cuối danh sách, trong khi tính năng Refresh giúp làm mới danh sách hiện tại.

Tại sao Load More và Refresh là quan trọng?

Khi xây dựng ứng dụng di động, trải nghiệm người dùng là yếu tố then chốt. Đối với các danh sách dài, việc tải một lượng lớn dữ liệu ngay từ đầu sẽ gây giảm hiệu suất. Để giải quyết vấn đề này, Load More cho phép người dùng tải từng phần dữ liệu.

Mặt khác, Refresh là tính năng quan trọng để cập nhật dữ liệu hiện tại khi người dùng muốn xem những thông tin mới nhất. Điều này tạo ra một trải nghiệm người dùng linh hoạt và luôn cập nhật.

Nói chung, mục đích của 2 tính năng này là giúp tăng trải nghiệm người dùng. Bài viết này mình chia sẻ dưới kinh nghiệm của bản thân, cũng xin góp ý từ các bạn để cải thiện.

Cùng bắt đầu nào )-_-(

Tạo ra các state:

 const limit = 10; const [data, setData] = useState([]); // Mục đich xử lý giao diện khi callApi const [UI, setUI] = useState(false); // Khi Loadmore mà hết dữ liệu =>>true const isStop = useRef<boolean>(false); // Hạn chế việc loading, luôn luôn 1 api được chạy const isLoading = useRef<boolean>(false);

Call Api (kết hợp Load more, Refresh):

const getData = async (type: "refresh" | "loadMore") => { if (isLoading.current == true) return; // Nếu đang loading mà vẫn gọi hàm ==> return if (type == "loadMore" && isStop.current == true) return; // Khi hết dữ liệu ==> return if (type == "refresh") { setData([]); isStop.current = false; } try { setUI(true); isLoading.current = true; //call api const response = await callApi({ skip: type == "loadMore" ? data.length : 0, limit: limit, }); // await new Promise((resolve) => setTimeout(resolve, 1000)); isLoading.current = false; if (response.products.length < limit) { isStop.current = true; } if (type == "refresh") { setData(response?.products); } if (type == "loadMore") { setData(data.concat(response?.products)); } } catch (error) { console.log(error); } finally { setUI(false); } };

Mình có sử dụng 1 api trên dummyjson

const callApi = async (data: { skip: number; limit: number }) => { try { const response = await fetch( `https://dummyjson.com/products?skip=${data.skip}&limit=${data.limit}` ); const result = await response.json(); console.log("Result:", result); return result; } catch (error) { console.log(error); }
};

Flatlist:

 <View style={{ flex: 1 }}> <HeaderScreen title="Flatlist" /> <FlatList data={data} keyExtractor={(item, idx) => idx + ""} renderItem={renderItem} onEndReachedThreshold={0.3} onEndReached={() => getData("loadMore")} refreshControl={ <RefreshControl refreshing={false} onRefresh={() => getData("refresh")} /> } ListFooterComponent={ <View style={{ alignItems: "center", marginVertical: 10 }}> {renderFooterList} </View> } /> </View>

Sử dụng listFooterComponent để thể hiện giao diện khi đang call api, danh sách sản phẩm trống, hoặc danh sách đã hết

 const renderFooterList = useMemo(() => { if (UI) return <ActivityIndicator color={"red"} />; if (data.length == 0 && isStop.current) return <Text>Danh sách trống</Text>; if (isStop.current) return <Text>Danh sách đã hết</Text>; return <View />; }, [UI]);

Dưới đây là full code, các bạn cùng trải nghiệm nhé

import HeaderScreen from "components/headers/HeaderScreen";
import React, { useEffect, useMemo, useRef, useState } from "react";
import { View, FlatList, RefreshControl, ActivityIndicator, Text,
} from "react-native"; const callApi = async (data: { skip: number; limit: number }) => { try { const response = await fetch( `https://dummyjson.com/products?skip=${data.skip}&limit=${data.limit}` ); const result = await response.json(); console.log("Result:", result); return result; } catch (error) { console.log(error); }
}; const Flatlist = () => { const limit = 10; const [data, setData] = useState([]); // Mục đich xử lý giao diện khi callApi const [UI, setUI] = useState(false); // Khi Loadmore mà hết dữ liệu =>>true const isStop = useRef<boolean>(false); // Hạn chế việc loading, luôn luôn 1 api được chạy const isLoading = useRef<boolean>(false); useEffect(() => { getData("refresh"); }, []); const getData = async (type: "refresh" | "loadMore") => { if (isLoading.current == true) return; // Nếu đang loading mà vẫn gọi hàm ==> return if (type == "loadMore" && isStop.current == true) return; // Khi hết dữ liệu ==> return if (type == "refresh") { setData([]); isStop.current = false; } try { setUI(true); isLoading.current = true; //call api const response = await callApi({ skip: type == "loadMore" ? data.length : 0, limit: limit, }); await new Promise((resolve) => setTimeout(resolve, 1000)); isLoading.current = false; if (response.products.length < limit) { isStop.current = true; } if (type == "refresh") { setData(response?.products); } if (type == "loadMore") { setData(data.concat(response?.products)); } } catch (error) { console.log(error); } finally { setUI(false); } }; const renderFooterList = useMemo(() => { if (UI) return <ActivityIndicator color={"red"} />; if (data.length == 0 && isStop.current) return <Text>Danh sách trống</Text>; if (isStop.current) return <Text>Danh sách đã hết</Text>; return <View />; }, [UI]); const renderItem = ({ item }: any) => { return ( <Text style={{ padding: 40, backgroundColor: item.id % 2 ? "#ffffff" : "#bbbbbb", }} > {item?.title} </Text> ); }; return ( <View style={{ flex: 1 }}> <HeaderScreen title="Flatlist" /> <FlatList data={data} keyExtractor={(item, idx) => idx + ""} renderItem={renderItem} onEndReachedThreshold={0.3} onEndReached={() => getData("loadMore")} refreshControl={ <RefreshControl refreshing={false} onRefresh={() => getData("refresh")} /> } ListFooterComponent={ <View style={{ alignItems: "center", marginVertical: 10 }}> {renderFooterList} </View> } /> </View> );
}; export default Flatlist; 

Bình luận