热搜:fiddler git ip ios 代理
历史搜索

React Native 应用中怎么添加刷新功能

游客2024-08-08 08:53:02
目录文章目录
  1. 项目设置
  2. 创建自定义钩子
  3. 设置加载器组件
  4. 构建项目组件
  5. 设置下拉刷新功能
  6. 自定义刷新控制
  7. 设置滚动刷新功能
  8. 结合刷新功能
  9. 小结

在这篇技术笔记中,我们将探讨如何在 React Native 应用程序中使用 FlatList 组件实现下拉刷新和滚动刷新功能。作为额外内容,我们将研究如何通过改变不同的参数,如大小和颜色,来自定义 RefreshControl 组件。要在 React Native 应用中实现刷新功能,我们可以利用 FlatList 组件的 refreshing 属性以及 onRefresh 回调函数。通过将 refreshing 属性与一个状态变量绑定,我们可以实现在下拉刷新时显示刷新指示器,并在刷新完成后隐藏它。要实现滚动刷新功能,我们可以使用 onEndReached 回调函数来监听列表滚动到底部的事件,并在需要时加载更多数据。另外,RefreshControl 组件提供了许多自定义选项,我们可以根据应用的需求进行调整。例如,我们可以通过设置 colors 属性来改变刷新指示器的颜色,通过设置 progressBackgroundColor 属性来改变刷新指示器的背景色。通过灵活运用这些方法,我们可以为我们的 React Native 应用添加强大的刷新功能,提升用户体验。

先来看一下最终实现效果:

React Native 应用中怎么添加刷新功能 1

结合刷新功能

接下来,我们将把下拉刷新功能和滚动刷新功能整合到一个 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 项目中实现下拉刷新和滚动刷新功能提供参考,感谢阅读!

标签:React