在这篇技术笔记中,我们将探讨如何在 React Native 应用程序中使用 FlatList 组件实现下拉刷新和滚动刷新功能。作为额外内容,我们将研究如何通过改变不同的参数,如大小和颜色,来自定义 RefreshControl 组件。要在 React Native 应用中实现刷新功能,我们可以利用 FlatList 组件的 refreshing 属性以及 onRefresh 回调函数。通过将 refreshing 属性与一个状态变量绑定,我们可以实现在下拉刷新时显示刷新指示器,并在刷新完成后隐藏它。要实现滚动刷新功能,我们可以使用 onEndReached 回调函数来监听列表滚动到底部的事件,并在需要时加载更多数据。另外,RefreshControl 组件提供了许多自定义选项,我们可以根据应用的需求进行调整。例如,我们可以通过设置 colors 属性来改变刷新指示器的颜色,通过设置 progressBackgroundColor 属性来改变刷新指示器的背景色。通过灵活运用这些方法,我们可以为我们的 React Native 应用添加强大的刷新功能,提升用户体验。
先来看一下最终实现效果:
结合刷新功能
接下来,我们将把下拉刷新功能和滚动刷新功能整合到一个 FlatList 组件中。
首先,打开 screens/Combined.jsx
文件并导入所需的依赖项和组件:
// JavaScript // screens/Combined.jsx import { FlatList, RefreshControl, StyleSheet, Text, View } from 'react-native'; import React, { useCallback, useEffect, useRef, useState } from 'react'; import { FETCH_RESULTS, useFetchUser } from '../hooks/useFetchUser'; import { Item } from '../components/Item'; import { Loader } from '../components/Loader';
接下来,我们创建我们的组件,并在两个地方调用 useFetchUser
Hook,用于顶部和底部的加载器,如下所示:
// JavaScript // screens/Combined.jsx const Combined = () => { const flatListRef = useRef(null); const { isLoading: isLoadingTop, success: successTop, users: usersTop, errorMessage: errorMessageTop, getUsers: getUsersTop, } = useFetchUser(); const { isLoading: isLoadingBottom, success: successBottom, users: usersBottom, errorMessage: errorMessageBottom, getUsers: getUsersBottom, } = useFetchUser(); return ( <View> </View> ) export default Combined;
在 JavaScript 中,我们可以通过在值后面加一个冒号来重命名一个解构的值:
const { isLoading } = useFetchUser(); // isLoading can be renamed to isLoadingTop const { isLoading: isLoadingTop } = useFetchUser();
现在,我们定义 combinedUsers
、 currentPage
、 refreshing
和 isTop
状态:
// JavaScript // screens/Combined.jsx const [combinedUsers, setConfirmedUsers] = useState([]); const [currentPage, setCurrentPage] = useState(1); const [refreshing, setRefreshing] = useState(false); const [isTop, setIsTop] = useState(false);
然后我们定义 loadMoreItem
函数:
// JavaScript // screens/Combined.jsx const loadMoreItem = () => { setCurrentPage((prev) => prev + 1); };
接下来,我们定义 onRefresh
回调和 scrollToItem
函数:
// JavaScript // screens/Combined.jsx const onRefresh = useCallback(() => { setRefreshing(true); setIsTop(true); loadMoreItem(); }, []); const scrollToItem = (index) => { flatListRef.current.scrollToIndex({ index: index, animated: false }); };
然后,我们定义 useEffect 钩子来获取数据:
// JavaScript // screens/Combined.jsx useEffect(() => { if (isTop) { getUsersTop(currentPage, isTop); } else { getUsersBottom(currentPage, isTop); } }, [currentPage]);
在上述代码中,我们检查 isTop
的值何时发生变化,以确定每次 currentPage
状态改变时调用的函数。
然后,我们为下拉刷新和滚动到底部的 API 请求成功时定义动作:
// JavaScript // screens/Combined.jsx useEffect(() => { if (successTop) { setRefreshing(false); setConfirmedUsers(usersTop); if (combinedUsers.length > 0) { scrollToItem(FETCH_RESULTS - 1); } } }, [successTop]); useEffect(() => { if (successBottom) { setConfirmedUsers(usersBottom); } }, [successBottom]);
接下来,我们像这样组合标记:
// JavaScript // screens/Combined.jsx <View> <Text style={{ textAlign: 'center', paddingVertical: 10, fontSize: 18, fontWeight: '600', }} > Combined Bidirectional FlatList </Text> {errorMessageTop ? <Text>{errorMessageTop}</Text> : null} <FlatList ref={flatListRef} data={combinedUsers} renderItem={Item} keyExtractor={(item) => item?.email} refreshControl={ <RefreshControl refreshing={refreshing} onRefresh={onRefresh} // tintColor='red' // colors={['red', 'green', 'blue']} // progressBackgroundColor={'green'} // title='Loading users...' // titleColor='green' // size={'large'} // progressViewOffset={200} // tintColor='transparent' // colors={['transparent']} // style={{ backgroundColor: 'transparent' }} /> } maxToRenderPerBatch={FETCH_RESULTS} // ListHeaderComponent={<Loader isLoading={refreshing} withText={true} />} ListFooterComponent={<Loader isLoading={isLoadingBottom} />} onEndReached={() => { loadMoreItem(); setIsTop(false); }} onEndReachedThreshold={0} ListEmptyComponent={<Loader isLoading />} initialScrollIndex={0} // Layout doesn't know the exact location of the requested element. // Falling back to calculating the destination manually onScrollToIndexFailed={({ index, averageItemLength }) => { flatListRef.current?.scrollToOffset({ offset: index * averageItemLength, animated: true, }); }} /> {errorMessageBottom ? <Text>{errorMessageBottom}</Text> : null} </View>
我们的组件应该看起来像这样:
// JavaScript // screens/Combined.jsx import { FlatList, RefreshControl, StyleSheet, Text, View } from 'react-native'; import React, { useCallback, useEffect, useRef, useState } from 'react'; import { FETCH_RESULTS, useFetchUser } from '../hooks/useFetchUser'; import { Item } from '../components/Item'; import { Loader } from '../components/Loader'; const Combined = () => { const flatListRef = useRef(null); const { isLoading: isLoadingTop, success: successTop, users: usersTop, errorMessage: errorMessageTop, getUsers: getUsersTop, } = useFetchUser(); const { isLoading: isLoadingBottom, success: successBottom, users: usersBottom, errorMessage: errorMessageBottom, getUsers: getUsersBottom, } = useFetchUser(); const [combinedUsers, setConfirmedUsers] = useState([]); const [currentPage, setCurrentPage] = useState(1); const [refreshing, setRefreshing] = useState(false); const [isTop, setIsTop] = useState(false); const loadMoreItem = () => { setCurrentPage((prev) => prev + 1); }; const onRefresh = useCallback(() => { setRefreshing(true); setIsTop(true); loadMoreItem(); }, []); const scrollToItem = (index) => { flatListRef.current.scrollToIndex({ index: index, animated: false }); }; useEffect(() => { if (isTop) { getUsersTop(currentPage, isTop); } else { getUsersBottom(currentPage, isTop); } }, [currentPage]); useEffect(() => { if (successTop) { setRefreshing(false); setConfirmedUsers(usersTop); if (combinedUsers.length > 0) { scrollToItem(FETCH_RESULTS - 1); } } }, [successTop]); useEffect(() => { if (successBottom) { setConfirmedUsers(usersBottom); } }, [successBottom]); return ( <View> <Text style={{ textAlign: 'center', paddingVertical: 10, fontSize: 18, fontWeight: '600', }} > Combined Bidirectional FlatList </Text> {errorMessageTop ? <Text>{errorMessageTop}</Text> : null} <FlatList ref={flatListRef} data={combinedUsers} renderItem={Item} keyExtractor={(item) => item?.email} refreshControl={ <RefreshControl refreshing={refreshing} onRefresh={onRefresh} // tintColor='red' // colors={['red', 'green', 'blue']} // progressBackgroundColor={'green'} // title='Loading users...' // titleColor='green' // size={'large'} // progressViewOffset={200} // tintColor='transparent' // colors={['transparent']} // style={{ backgroundColor: 'transparent' }} /> } maxToRenderPerBatch={FETCH_RESULTS} // ListHeaderComponent={<Loader isLoading={refreshing} withText={true} />} ListFooterComponent={<Loader isLoading={isLoadingBottom} />} onEndReached={() => { loadMoreItem(); setIsTop(false); }} onEndReachedThreshold={0} ListEmptyComponent={<Loader isLoading />} initialScrollIndex={0} // Layout doesn't know the exact location of the requested element. // Falling back to calculating the destination manually onScrollToIndexFailed={({ index, averageItemLength }) => { flatListRef.current?.scrollToOffset({ offset: index * averageItemLength, animated: true, }); }} /> {errorMessageBottom ? <Text>{errorMessageBottom}</Text> : null} </View> ); }; export default Combined; const styles = StyleSheet.create({});
要查看我们构建的内容,请更新 App.js
文件,如下所示:
// JavaScript // App.js import { StyleSheet, Text, View } from 'react-native'; import React from 'react'; import Combined from './screens/Combined'; const App = () => { return ( <View style={styles.container}> <Combined /> </View> ); }; export default App; const styles = StyleSheet.create({ container: { flex: 1, marginVertical: 40, marginHorizontal: 20, }, });
我们的最终应用程序应该像图一那样运行。
小结
在本篇技术笔记中,我们着重研究了如何在 React Native 项目中实现下拉刷新和滚动刷新功能,以及如何将这些功能结合起来。我们还讨论了如何定制刷新控制组件。
希望通过本教程能够对大家将来在 React Native 项目中实现下拉刷新和滚动刷新功能提供参考,感谢阅读!