javascript - React Native 如何使用 FlatList inside nativebase Tabs onEndReach keep fire non-stop

标签 javascript reactjs react-native native-base

我是 React Native 的新手,所以我使用了来自 3rd 方库的一些组件,并尝试尽可能使用 React Native 组件。

ReactNative:0.54 NativeBase:2.3.10 ....

我在基于 scrollView 的 Nativebase 的 Tabs 中遇到了 FlatList 问题

  1. onEndReachedThreshold 无法正常工作,因为 Doc 说 0.5 将触发项目的半程滚动但是当我设置 0.5 它不会触发最后一个项目的半程它等到滚动到最后一个项目并且它触发 onEndReach。

  2. 如果我使用 ListFooterComponent 来呈现加载,当数据未交付时它会不停地触发 onEndReach,我会遇到 onEndReach 问题。

这是我的代码

检查 Prop 和初始化状态

  static getDerivedStateFromProps(nextProps) {
    const { params } = nextProps.navigation.state;
    const getCategoryId = params ? params.categoryId : 7;
    const getCategoryIndex = params ? params.categoryIndex : 0;
    return {
      categoryId: getCategoryId,
      categoryIndex: getCategoryIndex,
    };
  }
  state = {
    loadCategoryTab: { data: [] },
    loadProduct: {},
    storeExistId: [],
    loading: false,
    refreshing: false,
  }

加载类别

 componentDidMount() { this.onLoadCategory(); }
  onLoadCategory = () => {
    axios.get(CATEGORY_API)
      .then((res) => {
        this.setState({ loadCategoryTab: res.data }, () => {
          setTimeout(() => { this.tabIndex.goToPage(this.state.categoryIndex); });
        });
      }).catch(error => console.log(error));
  }

检查 Tab 滑动或点击时的 onChange 事件

  onScrollChange = () => {
    const targetId = this.tabClick.props.id;
    this.setState({ categoryId: targetId });
    if (this.state.storeExistId.indexOf(targetId) === -1) {
      this.loadProductItem(targetId);
    }
  }
  loadProductItem = (id) => {
    axios.get(`${PRODUCT_API}/${id}`)
      .then((res) => {
        /*
        const {
          current_page,
          last_page,
          next_page_url,
        } = res.data;
        */
        this.setState({
          loadProduct: { ...this.state.loadProduct, [id]: res.data },
          storeExistId: this.state.storeExistId.concat(id),
        });
      })
      .catch(error => console.log(error));
  }

当onEndReach被触发时加载MoreProduct

  loadMoreProductItem = () => {
    const { categoryId } = this.state;
    const product = has.call(this.state.loadProduct, categoryId)
      && this.state.loadProduct[categoryId];
    if (product.current_page !== product.last_page) {
      axios.get(product.next_page_url)
        .then((res) => {
          const {
            data,
            current_page,
            last_page,
            next_page_url,
          } = res.data;
          const loadProduct = { ...this.state.loadProduct };
          loadProduct[categoryId].data = product.data.concat(data);
          loadProduct[categoryId].current_page = current_page;
          loadProduct[categoryId].last_page = last_page;
          loadProduct[categoryId].next_page_url = next_page_url;
          this.setState({ loadProduct, loading: !this.state.loading });
        }).catch(error => console.log(error));
    } else {
      this.setState({ loading: !this.state.loading });
    }
  }

渲染()

      render() {
        const { loadCategoryTab, loadProduct } = this.state;
        const { navigation } = this.props;
        return (
          <Container>
            <Tabs
              // NB 2.3.10 not fix yet need to use `ref` to replace `initialPage`
              ref={(component) => { this.tabIndex = component; }}
              // initialPage={categoryIndex}
              renderTabBar={() => <ScrollableTab tabsContainerStyle={styles.tabBackground} />}
              onChangeTab={this.onScrollChange}
              // tabBarUnderlineStyle={{ borderBottomWidth: 2 }}
            >
              {
                loadCategoryTab.data.length > 0 &&
                loadCategoryTab.data.map((parentItem) => {
                  const { id, name } = parentItem;
                  const dataItem = has.call(loadProduct, id) ? loadProduct[id].data : [];
                  return (
                    <Tab
                      key={id}
                      id={id}
                      ref={(tabClick) => { this.tabClick = tabClick; }}
                      heading={name}
                      tabStyle={styles.tabBackground}
                      activeTabStyle={styles.tabBackground}
                      textStyle={{ color: '#e1e4e8' }}
                      activeTextStyle={{ color: '#fff' }}
                    >
                      <FlatList
                        data={dataItem}
                        keyExtractor={subItem => String(subItem.prod_id)}
                        ListEmptyComponent={this.onFirstLoad}
                        // ListFooterComponent={this.onFooterLoad}
                        refreshing={this.state.refreshing}
                        onRefresh={this.handleRefresh}
                        onEndReachedThreshold={0.5}
                        onEndReached={() => {
                            this.setState({ loading: !this.state.loading }, this.loadMoreProductItem);
                        }}
                        renderItem={({ item }) => {
                          const productItems = {
                            item,
                            navigation,
                          };
                          return (
                            <ProductItems {...productItems} />
                          );
                        }}
                      />
// this OnLoadFooter is my tempory show loading without ListFooterComponent but i don't want to show loading outside FlatList hope i will get a help soon
                      <OnLoadFooter loading={this.state.loading} style={{ backgroundColor: '#fff' }} />
                    </Tab>
                  );
                })
              }
            </Tabs>
          </Container>
        );
      }

加载组件

function OnLoadFooter(props) {
  if (props.loading) return <Spinner style={{ height: 50, paddingVertical: 10 }} />;
  return null;
}

让我解释一下我的过程

  • 初始化标签的 CategoryId 和 CategoIndex

  • 在 axios fire 之后将获取所有类别并呈现 Tab 项目,因为当 initailPage 大于 0 时 nativebase Tabs 错误它显示空白页面并且当 this.tabIndex.goToPage 触发它调用时类别完成加载时我使用 ref 触发它onChange

  • onChage 事件开始检查 tabClick Ref 是否存在于 StoreExistId 中,当他们点击时保存类别,如果为真,我们加载产品,否则我们什么都不做。我需要 ref,因为 React 状态是异步的,这使得我的产品第一次加载重复数据,所以 Ref 来解决这个问题。

  • 当向下滚动到最后一项时,它将通过 API 分页加载更多产品

  • 我的数据状态如下 StoreExistId: [1,2,3,4] 加载产品:{ 1:{数据:[.....]}, 2:{数据:[.....]}, ETC.... }

先谢过

最佳答案

一些NativeBase组件内部使用了scrollView。我猜它可能是使用 ScrollView 的 ScrollableTab 组件?你不应该在 ScrollView 中使用 FlatList,那样的话 onReachEnd 将不起作用。

关于javascript - React Native 如何使用 FlatList inside nativebase Tabs onEndReach keep fire non-stop,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49490512/

相关文章:

javascript - Express.js elasticsearch 查询不起作用

javascript - 最小值和最大值的下拉列表,不在 EI9 和 IE8 JQuery 中更新

javascript - 无法将焦点从下拉菜单更改为文本字段

reactjs - 如何处理子元素的点击

javascript - React Hook useEffect 缺少依赖项 : 'init'

javascript - 如何在 typescript 中编写子类(React.Component)的类型定义?

android - 如何检查联系人是否下载了我的应用程序?

react-native - 程序类型已存在 : io. invertase.firebase.BuildConfig

reactjs - ReferenceError : window is not defined. 当我通过 jest 运行 npm test 进行单元测试时出现此错误

javascript - 即使我引用了 lib,$ 也未定义