9-8 RN之首页的上拉加载更多和下拉刷新

208 阅读2分钟

在本节中,我们将为首页列表添加上拉加载更多和下拉刷新功能。

一、下拉刷新功能

1. 配置 FlatList 属性

pages/Home/index.tsx 中,为 FlatList 添加 refreshingonRefresh 属性:

<FlatList
  refreshing={refreshing}
  onRefresh={onRefresh}
  data={channelList}
  renderItem={renderItem}
  keyExtractor={(item) => item.id}
  onEndReached={onEndReached}
  onEndReachedThreshold={0.2}
  ListFooterComponent={renderFooter}
  ListEmptyComponent={renderEmpty}
/>

2. 实现 onRefresh 方法

在组件中声明一个 refreshing 属性,并在 onRefresh 方法中调用数据请求:

interface IState {
  refreshing: boolean;
}

class Home extends React.Component<IProps, IState> {
  state = {
    refreshing: false,
  };

  onRefresh = () => {
    this.setState({
      refreshing: true,
    });
    const { dispatch } = this.props;
    dispatch({
      type: 'home/fetchChannels',
      callback: () => {
        this.setState({
          refreshing: false,
        });
      },
    });
  };
}

3. 更新 Model

models/home.ts 中,为 fetchChannels 方法添加回调:

*fetchChannels({ payload, callback }, { call, put, select }) {
  const { data } = yield call(axios.get, CHANNEL_URL, {
    params: payload,
  });

  const newChannels = data.results;

  if (payload && payload.loadMore) {
    const channels = yield select(({ home }: RootState) => home.channels);
    newChannels = channels.concat(newChannels);
  }

  yield put({
    type: 'setState',
    payload: {
      channels: newChannels,
      pagination: {
        current: data.pagination.current,
        total: data.pagination.total,
        hasMore: data.pagination.hasMore,
      },
    },
  });

  if (typeof callback === 'function') {
    callback();
  }
},

二、上拉加载更多功能

1. 配置 onEndReached 属性

FlatList 中添加 onEndReachedonEndReachedThreshold 属性:

onEndReachedThreshold={0.2}
onEndReached={this.onEndReached}

2. 实现 onEndReached 方法

Home 组件中声明 onEndReached 方法:

onEndReached = () => {
  const { dispatch, hasMore, loading } = this.props;
  if (loading || !hasMore) return;
  dispatch({
    type: 'home/fetchChannels',
    payload: {
      loadMore: true,
    },
  });
};

3. 更新 Model

models/home.ts 中,为 fetchChannels 方法添加分页逻辑:

*fetchChannels({ payload }, { call, put, select }) {
  const { pagination } = yield select(({ home }: RootState) => home);
  let currentPage = 1;
  if (payload && payload.loadMore) {
    currentPage = pagination.current + 1;
  }
  const { data } = yield call(axios.get, CHANNEL_URL, {
    params: {
      page: currentPage,
    },
  });

  const newChannels = data.results;
  if (payload && payload.loadMore) {
    const channels = yield select(({ home }: RootState) => home.channels);
    newChannels = channels.concat(newChannels);
    currentPage = data.pagination.current;
  }

  yield put({
    type: 'setState',
    payload: {
      channels: newChannels,
      pagination: {
        current: currentPage,
        total: data.pagination.total,
        hasMore: newChannels.length < data.pagination.total,
      },
    },
  });
},

三、尾部和空列表处理

1. 渲染尾部组件

添加 ListFooterComponentListEmptyComponent 属性:

ListFooterComponent={this.renderFooter}
ListEmptyComponent={this.renderEmpty}

2. 实现 renderFooterrenderEmpty

renderFooter = () => {
  const { hasMore, loading } = this.props;
  if (!hasMore) {
    return (
      <View style={styles.end}>
        <Text>我是有底线的</Text>
      </View>
    );
  }
  if (loading && hasMore) {
    return (
      <View style={styles.loading}>
        <Text>正在加载中...</Text>
      </View>
    );
  }
  return null;
};

renderEmpty = () => {
  const { loading } = this.props;
  if (!loading) {
    return (
      <View style={styles.empty}>
        <Text>暂无数据</Text>
      </View>
    );
  }
  return null;
};

3. 定义样式

const styles = StyleSheet.create({
  end: {
    alignItems: 'center',
    paddingVertical: 10,
  },
  loading: {
    alignItems: 'center',
    paddingVertical: 10,
  },
  empty: {
    alignItems: 'center',
    paddingVertical: 100,
  },
});

四、总结

在本节中,我们为首页列表添加了上拉加载更多和下拉刷新功能。通过配置 FlatList 的属性和实现相应的逻辑,用户可以流畅地加载更多数据和刷新列表。下一节,我们将继续完善首页的功能。