react-infinite-scroller icon indicating copy to clipboard operation
react-infinite-scroller copied to clipboard

loadmore gets called infinitely

Open mrchief opened this issue 7 years ago • 14 comments

I have a tree component and I'm trying to display 100 items at a time. I don't have any ajax calls to make to load next set of item.

Here's what the code looks like:

class Tree extends Component {
  static propTypes = {
    searchModeOn: PropTypes.bool
  }

  constructor(props) {
    super(props)

    this.pageSize = 100

    this.computeInstanceProps(props)

    this.state = {
      items: this.allVisibleNodes.slice(0, this.pageSize),
      hasMore: this.hasMore()
    }
  }

  componentWillReceiveProps = nextProps => {
    this.computeInstanceProps(nextProps)
    this.setState({ items: this.allVisibleNodes.slice(0, this.pageSize), hasMore: this.hasMore() })
  }

  computeInstanceProps = props => {
    this.allVisibleNodes = props.items            // props.items is the list of all items. 
    this.totalPages = this.allVisibleNodes.length / this.pageSize
    this.currentPage = 1
  }

  hasMore = () => {
    return this.currentPage <= this.totalPages
  }

  loadMore = page => {
    const start = this.pageSize * (page - 1)
    const nextItems = this.allVisibleNodes.slice(start, start + this.pageSize)
    this.currentPage = page
    this.setState({ items: nextItems, hasMore: this.hasMore() })
  }

  render() {
    console.log('re', this.props, this.state)
    const { searchModeOn } = this.props

    return (
      <ul className={`root ${searchModeOn ? 'searchModeOn' : ''}`}>
        <InfiniteScroll
          pageStart={0}
          initialLoad
          loadMore={this.loadMore}
          hasMore={this.state.hasMore}
          loader={
            <div className="loader" key={0}>
              Loading ...
            </div>
          }
          useCapture
          useWindow={false}
        >
          {this.state.items}
        </InfiniteScroll>
      </ul>
    )
  }
}

I've tried various combinations of initialLoad, hasMore, loadMore but either it stops after first load or keeps firing loadMore until it has reached the last page (the above code will keep firing loadMore)

ezgif com-optimize

mrchief avatar Apr 20 '18 01:04 mrchief

Face with same issue. Looks like a bit incorrect algorithm of calucating 'offset' variable - it always negative if you container style is set 'incorrect;y'. SO it should be either overflow: hidden or display: flex; flex-wrap: wrap; I'd recommend to add this somewhere into description.

makdv avatar Apr 23 '18 09:04 makdv

I recently updated the issue templates on this repo so that I can identify the bugs with this repo.

Please clone your layout and use of react-infinite-scroller by forking this Code Sandbox and linking it here. Doing so will massively expedite getting the bug fixed! 👊

danbovey avatar May 14 '18 19:05 danbovey

I was facing the same issue. In my case, the problem was caused by items with unequal heights. Once, I adjusted the heights of all items to be equal, everything worked fine.

krinnewitz avatar May 20 '18 21:05 krinnewitz

This is a blocker issue for me too. If hasMore is true, loadMore is called endlessly. Setting equal row heights doesn't help.

sandorvasas avatar Aug 27 '18 08:08 sandorvasas

I've found unnecessary state updates can cause infinite loops with this library. What solved it for me was setting the hasMore state property to be a boolean rather than a function. Do a check in your loadMore function and only call setState to set it to false once you've reached the end.

In other words, stop updating the hasMore state every load, guard it with an if check.

JakeAngell avatar Feb 14 '19 10:02 JakeAngell

Set a lock like loading to prevent infinite loops

async function loadMore() {
  if (this.state.loading) {
    return 
  }

  this.setState({ loading: true })
  await fetchUser()
  this.setState({ loading: false)
}

lyyourc avatar Feb 25 '19 05:02 lyyourc

@lyyourc Your solution is the best option IMHO

Eli-Goldberg avatar Mar 20 '19 19:03 Eli-Goldberg

Set a lock like loading to prevent infinite loops

async function loadMore() {
  if (this.state.loading) {
    return 
  }

  this.setState({ loading: true })
  await fetchUser()
  this.setState({ loading: false)
}

Great solution. Had 2 components that were almost the same. But one worked fine and the other would call loadMore infinitely for whatever reason. This solution fixed the problem Thanks!

imjamesku avatar Oct 09 '19 00:10 imjamesku

Set a lock like loading to prevent infinite loops

async function loadMore() {
  if (this.state.loading) {
    return 
  }

  this.setState({ loading: true })
  await fetchUser()
  this.setState({ loading: false)
}

I encountered a situation that loadMore was called repeatedly unexpected times. This solution really fixed this problem. Thanks

lynda0214 avatar May 05 '20 07:05 lynda0214

So if this is the solution, then I guess we just need it documented and then close this issue? What do the authors think?

mrchief avatar May 05 '20 19:05 mrchief

LGTM

On Tue, May 5, 2020, 22:54 Hrusikesh Panda [email protected] wrote:

So if this is the solution, then I guess we just need it documented and then close this issue? What do the authors think?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/CassetteRocks/react-infinite-scroller/issues/149#issuecomment-624272595, or unsubscribe https://github.com/notifications/unsubscribe-auth/AESSMXE7MIYN4OJDFVHXGFDRQBVI3ANCNFSM4E3S6OLA .

Eli-Goldberg avatar May 06 '20 07:05 Eli-Goldberg

I faced the same issue, how to fix?

xfantasy avatar May 07 '20 07:05 xfantasy

I faced the same issue, how to fix?

Have you tried the lock method mentioned above?

lynda0214 avatar May 07 '20 08:05 lynda0214

For those using functional react to accomplish this, you will also have to set awaits on your setState methods as react hooks for useState are asynchronous

const onLoadMore = async () => {
    if (listIsLoading) {
      return;
    }
    await setListIsLoading(true);
    await fetchMore();
    await setListIsLoading(false);
};

raymondshiner avatar Aug 03 '20 23:08 raymondshiner