【问题标题】:How to make infinite scroll fetch function work in order如何使无限滚动获取功能按顺序工作
【发布时间】:2018-12-21 13:41:07
【问题描述】:

我想无限滚动来获取任何项目,简单的步骤是:

1) 在屏幕末尾滚动。

2) 使用 redux 更新项目 pageIndex。

3) 使用 componentDidUpdate 来捕捉这个 redux 动作。

4) 将获取的项目附加到项目数组的末尾。

class InfiniteScroll extends React.Component {
  componentDidMount() {
    window.addEventListener("scroll", throttle(this.onScroll, 500), false);
  }
  componentWillUnmount() {
    window.removeEventListener("scroll", this.onScroll, false);
  }
  componentDidUpdate(preProps) {
    if (props.pageindex === preProps.pageindex + 1)
      fetchItems(...);
  }
  onScroll = () => {
    if (
      window.innerHeight + window.scrollY >=
      document.body.offsetHeight - 100
    ) {
      updatePage(...);
    }
  };
  render() {
    return <Component {...this.props} />;
  }
}

此代码的唯一问题是当updatePage 执行一次时,fetchItems 无法立即执行。

【问题讨论】:

  • fetchItems 无法立即关注”是什么意思?你能展示更多你的代码吗(例如updatePagefetchItems在做什么)?
  • 无限滚动来获取东西就像 onPaginated 来显示项目一样,除了你打算在页面末尾滚动而不是点击 next-page 按钮。

标签: reactjs redux fetch throttling react-thunk


【解决方案1】:

由于您使用的是 redux,因此您的项目列表应通过操作/reducer 控制。

InfiniteScroll.js:

onScroll () {
    var nearBottom = window.innerHeight + window.scrollY >= document.body.offsetHeight - 100;
    if (!this.props.fetching && nearBottom) {
        fetchItems();  // dispatch action
    }
}

render () {
    var items = this.props.items.map(item => (<Component {item}/>)

    return (
        <ul>{ items }</ul>
    )
}

componentDidMount() {
    window.addEventListener("scroll", this.onScroll.bind(this), false);
}
componentWillUnmount() {
    window.removeEventListener("scroll", this.onScroll.bind(this), false);
}

行动:

fetchItems () {
    return dispatch => {
        dispatch({
            type: "FETCH_ITEMS"
        });
        fetch("/api/items")
        .then(items => {
            dispatch(itemsReceived(items));
        });
    }
}
itemsReceived (items) {
    return {
        type: "ITEMS_RECEIVED",
        payload: {
            items: items
        }
    }
}

减速器:

case "FETCH_ITEMS":
    return {
        ...prevState,
        fetching: true

case "ITEMS_RECEIVED":
    return {
        ...prevState,
        fetching: false,
        items: prevState.items.concat(items)
    }

这样,滚动触发一个明确定义的动作(FETCH_ITEMS)。使用redux-thunk,该操作会调用API 来获取新项目。当该调用完成后,您将调度一个新操作以通过 reducer 提供新项目。

reducer 然后更新状态,导致&lt;InfiniteScroll&gt; 重新渲染更新的项目列表。

注意:如果出现错误,您还应该将 fetching 设置为 false。

【讨论】:

  • 这很可能是我的reducer,但是触发onScroll时fetchItems会执行很多次。可以使用lodash的throttle限制执行一次,但是也有问题。
  • 您可以做的一件事是在当前正在进行提取时强制执行限制行为。这在你的减速器中很容易做到。请参见上面的示例。请注意,无论何时进行提取fetching 将如何为真,从而防止另一个请求触发。收到商品后,页面会更新,滚动将再次触发获取请求。
【解决方案2】:

如果我是你,我会使用图书馆为我完成繁重的工作。

一个选项是react-infinite-scroller

以下是您的用例的样子,大部分是伪代码:

<InfiniteScroll
    pageStart={0}
    loadMore={fetchItems} // that's your method for loading more results
    hasMore={props.pageindex === preProps.pageindex + 1} // your 'has more' logic
    loader={<div className="loader">Loading ...</div>}
>
    {items} // <-- This is the content you want to load
</InfiniteScroll>

对于一个工作示例,check out the demo in their repo


另一种选择是尝试调试您的代码。但是您需要提供更多上下文。从你提供的信息来看,真的很难判断是哪里出了问题。

【讨论】:

  • 我会尽量自己先完成,对不起。
  • 好的。我想帮助你,但我没有足够的上下文。更新您的问题并解释究竟是什么问题。试着做一个完整的例子,也许有人可以调试它。
猜你喜欢
  • 2013-12-21
  • 2020-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多