Компонент Infinite Scroll React загружает только один новый фрагмент объектов при прокрутке вниз и затем останавливается

У меня есть компонент React, который должен загружать 6 изображений за раз, когда страница прокручивается ниже. Я хочу использовать типичный эффект бесконечной прокрутки, который теперь используют YouTube и Reddit.

Прямо сейчас страница открывается как надо с 6 загруженными изображениями. Когда я прокручиваю вниз приложение загружает еще 6, но затем оно останавливается. Всего 25 изображений. Я считаю 13 изображений, которые по какой-то причине не загружаются. Предполагается, что приложение будет продолжать загружать изображения 6 одновременно с прокруткой вниз, пока не останется больше изображений для загрузки.

Я использую компонент бесконечной прокрутки здесь . Я попытался установить более старую версию «4.5.2», и это тоже не сработало.

Снимок экрана приложения внизу показывает кнопки вверху, которые добавляют или удаляют 6 изображений.
Первое число показывает приращение 6 изображений. (Это 0, когда 6 изображений отображаются, и 1, когда 12 отображаются.)
Число ниже показывает общее количество изображений (URL-адреса изображений в JSON-объекте, полученном приложением от серверной части).

    import React, { ListView } from 'react'
    import InfiniteScroll from 'react-infinite-scroll-component'

    export default class Fb_grid extends React.Component {
        constructor(props) {
            super(props)
            this.state = {
            apiResponse: [],
            page: 0
            }
        }
        componentDidMount() {
        this.callAPI();
        }

        callAPI() {
            fetch('/api/getList')
                .then(res => res.json())
                .then(res => this.setState({ apiResponse: res }))
        }

        next = () => {
        this.setState({ page: this.state.page+1 })
        }

        render() {
            const { apiResponse } = this.state;
            const { page } = this.state;

            if(!apiResponse) {
                return <p className="row">Loading</p>
            }
            return(
            <div className="App">
                <div className="row">
                <button className="testButton" onClick={this.previous}>LESS</button>
                <button className="testButton" onClick={this.next}>MORE</button>
                <br/>{page}<br/>{apiResponse.length}<div className="spacer"/>
                </div>
                <div className="row">
                    <InfiniteScroll
                    dataLength={apiResponse.length}
                    next={this.next}
                    hasMore={true}
                    >
                        {Object.values(apiResponse.slice(0, (this.state.page+1)*6)).map((value, index) => 
                        <a target="_blank" rel="noopener noreferrer" href={value.post}>
                            <img src={value.image} className="image"/>
                        </a>)}
                    </InfiniteScroll>
                </div>
            </div>
            )
        }
    }

Снимок экрана приложения

Если вы хотите запустить этот компонент на своем компьютере, вы, вероятно, захотите, чтобы ваш собственный JSON хранился локально в компоненте. Конечно, вам также нужно будет настроить Object.values(apiResponse.slice(0, (this.state.page+1)*6)).map соответствующим образом.
Вот как выглядят данные JSON, которые использует мой компонент. 25 объектов с URL-адресом изображения и ссылкой для тега <a> в котором отображается изображение.

[{"image":"https://cdn.mos.cms.futurecdn.net/vChK6pTy3vN3KbYZ7UU7k3.jpg","post":"http://www.google.com"},
{"image":"https://cdn.mos.cms.futurecdn.net/vChK6pTy3vN3KbYZ7UU7k3.jpg","post":"http://www.google.com"},
{"image":"https://cdn.mos.cms.futurecdn.net/vChK6pTy3vN3KbYZ7UU7k3.jpg","post":"http://www.google.com"},
{"image":"https://cdn.mos.cms.futurecdn.net/vChK6pTy3vN3KbYZ7UU7k3.jpg","post":"http://www.google.com"},
{"image":"https://cdn.mos.cms.futurecdn.net/vChK6pTy3vN3KbYZ7UU7k3.jpg","post":"http://www.google.com"},
{"image":"https://cdn.mos.cms.futurecdn.net/vChK6pTy3vN3KbYZ7UU7k3.jpg","post":"http://www.google.com"},
{"image":"https://cdn.mos.cms.futurecdn.net/vChK6pTy3vN3KbYZ7UU7k3.jpg","post":"http://www.google.com"},
{"image":"https://cdn.mos.cms.futurecdn.net/vChK6pTy3vN3KbYZ7UU7k3.jpg","post":"http://www.google.com"},
{"image":"https://cdn.mos.cms.futurecdn.net/vChK6pTy3vN3KbYZ7UU7k3.jpg","post":"http://www.google.com"},
{"image":"https://cdn.mos.cms.futurecdn.net/vChK6pTy3vN3KbYZ7UU7k3.jpg","post":"http://www.google.com"},
{"image":"https://cdn.mos.cms.futurecdn.net/vChK6pTy3vN3KbYZ7UU7k3.jpg","post":"http://www.google.com"},
{"image":"https://cdn.mos.cms.futurecdn.net/vChK6pTy3vN3KbYZ7UU7k3.jpg","post":"http://www.google.com"},
{"image":"https://cdn.mos.cms.futurecdn.net/vChK6pTy3vN3KbYZ7UU7k3.jpg","post":"http://www.google.com"},
{"image":"https://cdn.mos.cms.futurecdn.net/vChK6pTy3vN3KbYZ7UU7k3.jpg","post":"http://www.google.com"},
{"image":"https://cdn.mos.cms.futurecdn.net/vChK6pTy3vN3KbYZ7UU7k3.jpg","post":"http://www.google.com"},
{"image":"https://cdn.mos.cms.futurecdn.net/vChK6pTy3vN3KbYZ7UU7k3.jpg","post":"http://www.google.com"},
{"image":"https://cdn.mos.cms.futurecdn.net/vChK6pTy3vN3KbYZ7UU7k3.jpg","post":"http://www.google.com"},
{"image":"https://cdn.mos.cms.futurecdn.net/vChK6pTy3vN3KbYZ7UU7k3.jpg","post":"http://www.google.com"},
{"image":"https://cdn.mos.cms.futurecdn.net/vChK6pTy3vN3KbYZ7UU7k3.jpg","post":"http://www.google.com"},
{"image":"https://cdn.mos.cms.futurecdn.net/vChK6pTy3vN3KbYZ7UU7k3.jpg","post":"http://www.google.com"},
{"image":"https://cdn.mos.cms.futurecdn.net/vChK6pTy3vN3KbYZ7UU7k3.jpg","post":"http://www.google.com"},
{"image":"https://cdn.mos.cms.futurecdn.net/vChK6pTy3vN3KbYZ7UU7k3.jpg","post":"http://www.google.com"},
{"image":"https://cdn.mos.cms.futurecdn.net/vChK6pTy3vN3KbYZ7UU7k3.jpg","post":"http://www.google.com"},
{"image":"https://cdn.mos.cms.futurecdn.net/vChK6pTy3vN3KbYZ7UU7k3.jpg","post":"http://www.google.com"},
{"image":"https://cdn.mos.cms.futurecdn.net/vChK6pTy3vN3KbYZ7UU7k3.jpg","post":"http://www.google.com"}]

Всего 1 ответ


Вы можете использовать следующий ленивый компонент загрузки

    import React, { Component } from 'react'
    import PropTypes from 'prop-types'

    const LoaderComponent = () => (
      <div className='loader' >
        <div className='loader-text'>Loading...</div>
      </div>
    )

    class LazyLoadOnBody extends Component {
      constructor (props) {
        super(props)
        this.state = {
          loadMore: true,
          footer: this.props.footerHeight
        }
        this.onScroll = this.onScroll.bind(this)
      }

      componentDidMount () {
        window.addEventListener('scroll', this.onScroll, false)
      }

      componentWillReceiveProps (nextProps) {
        if (nextProps.currentTotal !== this.props.currentTotal) {
          this.setState({
            loadMore: true
          })
        }
      }

      componentWillUnmount () {
        window.removeEventListener('scroll', this.onScroll)
      }

      onScroll () {
        const windowHeight = 'innerHeight' in window ? window.innerHeight : document.documentElement.offsetHeight
        const { scrollHeight, offsetHeight } = document.body
        const { clientHeight } = document.documentElement
        const scrollHeightHtml = document.documentElement.scrollHeight
        const offsetHeightHtml = document.documentElement.offsetHeight
        const bodyHeight = Math.max(scrollHeight, offsetHeight)
        const docHeight = Math.max(bodyHeight, clientHeight, scrollHeightHtml, offsetHeightHtml)
        const windowBottom = windowHeight + window.pageYOffset
        const { total, currentTotal } = this.props
        if (windowBottom >= docHeight - 150 - this.state.footer && total > currentTotal) {
          if (this.state.loadMore) {
            this.props.loadMoreRows()
          }
          this.setState({
            loadMore: false
          })
        }
      }

      render () {
        return (
          <div className={this.props.className} >
            {this.props.children}
            {!this.state.loadMore ? this.props.loader : null}
          </div>
        )
      }
    }

    LazyLoadOnBody.propTypes = {
      total: PropTypes.number,
      currentTotal: PropTypes.number,
      loadMoreRows: PropTypes.func.isRequired,
      children: PropTypes.oneOfType([
        PropTypes.arrayOf(PropTypes.node),
        PropTypes.node
      ]),
      footerHeight: PropTypes.number,
      loader: PropTypes.node,
      className: PropTypes.string,
    }

    LazyLoadOnBody.defaultProps = {
      children: null,
      footerHeight: 0,
      loader: <LoaderComponent />,
      className: '',
      total: 0,
      currentTotal: 0
    }

    export default LazyLoadOnBody

и вы можете обновить свой код соответственно

import React from 'react'
import LazyLoadBody from '../LazyLoadBody'

const Loader = () => (
  <div
    style={{
      display: 'flex',
      alignItems: 'center',
      justifyContent: 'center',
      height: 50
    }}
  >
    Loading...
  </div>
)

export default class FbGrid extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      apiResponse: [],
      page: 0
    }
  }
  componentDidMount() {
    this.callAPI();
  }

  callAPI() {
    fetch('/api/getList')
      .then(res => res.json())
      .then(res => this.setState({ apiResponse: res }))
  }

  loadMoreRows = () => {
    this.setState({ page: this.state.page + 1 })
  }

  render() {
    const { apiResponse, page } = this.state;

    if (!apiResponse) {
      return <p className="row">Loading...</p>
    }
    return (
      <div className="App">
        <div className="row">
          <br />{page}<br />{apiResponse.length}<div className="spacer" />
        </div>
        <LazyLoadOnBody loader={<Loader />} total={this.state.apiResponse.length} currentTotal={(page + 1) * 6} loadMoreRows={() => this.loadMoreRows()} >
          <div className='row' >
            {Object.values(apiResponse.slice(0, (page + 1) * 6)).map((value, i) => (
              <a key={i} target="_blank" rel="noopener noreferrer" href={value.post}>
                <img alt='' src={value.image} className="image" />
              </a>
            ))}
          </div>
        </LazyLoadOnBody>
      </div>
    )
  }
}

Есть идеи?

10000