Вопрос по infinite-scroll, html, reactjs, javascript – Бесконечная прокрутка с React JS

75

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

Здесьjsfiddle проблема. В этой задаче я хочу, чтобы в DOM одновременно было только 50 элементов. другие должны быть загружены и удалены как пользователь прокручивает вверх и вниз. Из-за этого мы начали использовать React.алгоритмы оптимизации. Теперь я не могне могу найти решение этой проблемы. Я сталкивалсяairbnb бесконечный JS, Но это реализовано с помощью Jquery. Чтобы использовать эту бесконечную прокрутку airbnb, мне нужно потерять оптимизацию React, которую я нене хочу делать.

Пример кода, который я хочу добавить, - это прокрутка (здесь я загружаю все элементы. Моя цель - загружать только 50 элементов одновременно)

/** @jsx React.DOM */

var Hello = React.createClass({
    render: function() {
        return (Hello {this.props.name});
    }
});

var HelloList = React.createClass({ 
     getInitialState: function() {                            
         var numbers =  [];
         for(var i=1;i

Ваш Ответ

4   ответа
15

Концепция бесконечной прокрутки с использованием React Js

Мы можем заставить бесконечную прокрутку работать, слушая событие прокрутки. Мы можем добавить прослушиватель событий либо к самому родительскому элементу div, либо даже к объекту window.

Посмотрите на следующий код

   render() {
        return (
          
            Hurrah! My First React Infinite Scroll
            

            
          
        );
    }

Код выше имеет простой тег ul; внутри которого мы будем связывать извлеченные предметы. Этот тег окружен элементом div, к которому мы собираемся присоединить прослушиватель событий для прослушивания события прокрутки.

Я надеюсь, что вы знаете обо всех тегах, используемых здесь. Арен»ты? Ну, некоторые из вас, возможно, не знакомы с реф! Таким образом, ref используется для определения ссылки на разделение (div) или любой другой элемент html. Используя эту ссылку, вы можете удержать этот элемент в реакции. Мы дали ссылку имя «iScroll» и вы можете получить доступ к этому div с помощью this.refs.iScroll.

Убедитесь, что высота div меньше, чем общая высота основного показа предметов, которые вы выигралиполучить полосу прокрутки. Вы можете установить высоту на 100% или использовать объект окна вместо нашего iScroll div, чтобы выполнить прокрутку на уровне окна.

Теперь давайтепоговорим о конструкторе, который будет выглядеть так:

constructor(props) {
    super(props);
    this.state = {
      items: 10,
      loadingState: false
    };
}

Здесь есть два свойства в объекте состояния; элементы и загрузкаState. Элементы означают количество доступных элементов, которые могут быть включены как lis в раздел ul, а loadState использовался для отображения загрузки текста ... при загрузке данных. Поскольку мы просто предоставляем демо, этоПочему в качестве предметов используется число. В реальном приложении вы, вероятно, будете хранить свой фактический список данных там.

После этого вы создадите функцию, которая будет отображать все элементы:

displayItems() {
    var items = [];
    for (var k = 0; k < this.state.items; k++) {
      items.push(Item-VoidCanvas {k});
    }
    return items;
}

Эта функция создает список li и отображает все элементы. Опять же, как этоДемо, мы показываем, используя номер. В реальных приложениях вам нужно перебирать массив элементов и отображать содержащиеся в нем значения.

Обновите функцию рендеринга сейчас:

render() {
    return (
      
        Hurrah! My First React Infinite Scroll
        
          {this.displayItems()}
        
        {this.state.loadingState
          ? <p classname="loading">
          loading More Items..
        </p>
          : ""}
      
    );
} 

Да, это обычный компонент, отображающий несколько литов. Как это делает его бесконечно прокручиваемым? Надеюсь, вы помните, что ранее мы использовали ссылку с именем iScroll, теперь она вступает в действие.

componentDidMount() {
    this.refs.iScroll.addEventListener("scroll", () => {
 ,     if (
        this.refs.iScroll.scrollTop + this.refs.iScroll.clientHeight >=
        this.refs.iScroll.scrollHeight
      ) {
        this.loadMoreItems();
      }
    });
}

Как вы все знаете, у реагирующих компонентов есть функция componentDidMount (), которая вызывается автоматически, когда шаблон этого компонента отображается в DOM. И я использовал ту же функцию, чтобы добавить прослушиватель событий для прокрутки в наш div iScroll. Свойство scrollTop элемента найдет позицию прокрутки и ее свойство clientHeight. Затем условие if проверит, что добавление этих двух свойств больше или равно высоте полосы прокрутки или нет. Если условие истинно, функция loadMoreItems будет запущена.

Вот как будет выглядеть функция:

loadMoreItems() {
    if(this.state.loadingState){
        return;
    }
    this.setState({ loadingState: true });
    // you may call ajax instead of setTimeout
    setTimeout(() => {
        this.setState({ items: this.state.items + 10, loadingState: false });
    }, 1000);
}

Это довольно просто, сначала установите для loadingState значение true, и div загрузки будет отображаться (как показано в функции рендеринга). Затем вызывается функция setTimeout, которая увеличит количество элементов на 10 и снова сделает loadState ложным. Здесь причина, по которой мы используем setTimeout, заключается в создании временной задержки. В реальных приложениях вы, вероятно, сделаете ajax-вызов на свой сервер, и при разрешении этого вы будете выполнять аналогичные действия, которые выполняются с помощью обратного вызова нашего setTimeout. Полный фрагмент кода здесь:

class Layout extends React.Component {
  constructor(props) {
   super(props);
   this.state = {
      items: 10,
      loadingState: false
    };
  }

  componentDidMount() {
    this.refs.iScroll.addEventListener("scroll", () => {
      if (this.refs.iScroll.scrollTop + this.refs.iScroll.clientHeight >= this.refs.iScroll.scrollHeight - 20){
        this.loadMoreItems();
      }
    });
  }

  displayItems() {
    var items = [];
    for (var i = 0; i < this.state.items; i++) {
      items.push(Item {i});
    }
    return items;
  }

  loadMoreItems() {
	 if(this.state.loadingState){
		 return;
	 }
    this.setState({ loadingState: true });
    setTimeout(() => {
      this.setState({ items: this.state.items + 10, loadingState: false });
    }, 1000);
  }

  render() {
    return (
      
        
          {this.displayItems()}
        

        {this.state.loadingState ? <p classname="loading"> loading More Items..</p> : ""}

      
    );
  }
}

ReactDOM.render(, document.getElementById('example'));



Я сделал upvote, но слушатель события не слушает событие прокрутки моего div Shivansh Jagga
Upvote для всестороннего объяснения. Yashwin Munsadwala
21

Посмотрите нашу библиотеку React Infinite:

https://github.com/seatgeek/react-infinite

Обновление декабря 2016

вы на самом деле использовалиреагируют-виртуализированы Во многих моих проектах в последнее время я обнаружил, что он намного лучше покрывает большинство вариантов использования. Обе библиотеки хороши, это зависит от того, что выищу. Например, Reaction-Virtualized поддерживает измерение JIT переменной высоты через HOC, называемыйCellMeasurerпример тутhttps://bvaughn.github.io/react-virtualized/#/components/CellMeasurer.

Обновление ноябрь 2018

Многие уроки из реагирующей виртуализации были перенесены на меньшие, более быстрые и эффективныереагирует окно Библиотека от того же автора.

Спасибо за поддержку этого ответа! Scott Sword
@Druska, Технически да, однако вы также можете использовать окно в качестве контейнера прокрутки, используя опцию useWindowAsScrollContainer. HussienK
Это действительно так,github.com/bvaughn/react-virtualized/blob/master/docs/Grid.md Zach
Эта библиотека работает, только если вы знаете высоту ваших элементов перед рендерингом. Druska
53

В основном, при прокрутке вы хотите решить, какие элементы являются видимыми, а затем выполнить повторное отображение, чтобы отобразить только эти элементы, с одним элементом распорки сверху и снизу для представления элементов вне экрана.

Vjeux сделал скрипку, на которую вы можете посмотреть:

http://jsfiddle.net/vjeux/KbWJ2/9/

При прокрутке выполняется

scrollState: function(scroll) {
    var visibleStart = Math.floor(scroll / this.state.recordHeight);
    var visibleEnd = Math.min(visibleStart + this.state.recordsPerBody, this.state.total - 1);

    var displayStart = Math.max(0, Math.floor(scroll / this.state.recordHeight) - this.state.recordsPerBody * 1.5);
    var displayEnd = Math.min(displayStart + 4 * this.state.recordsPerBody, this.state.total - 1);

    this.setState({
        visibleStart: visibleStart,
        visibleEnd: visibleEnd,
        displayStart: displayStart,
        displayEnd: displayEnd,
        scroll: scroll
    });
},

и тогда функция рендеринга отобразит только строки в диапазоне.displayStart..displayEnd

Вы также можете быть заинтересованы вReactJS: Моделирование двунаправленной бесконечной прокрутки.

@ sophie-alpert: возможно ли обновить jsfiddle? Я знаю, что вы будете заняты, но если вы сможете обновить его, это принесет пользу многим, таким как я: D john sam
Ничего не появляется в скрипке. Кнопки генерации появляются, но больше ничего. thund
@manalang Я второй, что - еще удачи? Alex McMillan
Пример jsfiddle не работает на Chrome. angry kiwi
1
import React, { Component } from 'react';
import InfiniteScroll from 'react-infinite-scroller';


const api = {
    baseUrl: '/joblist'
};

class Jobs extends Component {
    constructor(props) {
            super(props);
            this.state = {
                listData: [],
                hasMoreItems: true,
                nextHref: null
        };
    }

    fetchData(){
            var self = this;           
            var url = api.baseUrl;
            if(this.state.nextHref) {
                url = this.state.nextHref;
            }

            fetch(url)
            .then( (response) => {
                return response.json() })   
                    .then( (json) => {
                        var list = self.state.listData;                        
                        json.data.map(data => {
                            list.push(data);
                        });

                        if(json.next_page_url != null) {
                            self.setState({
                                nextHref: resp.next_page_url,
                                listData: list                               
                            });
                        } else {
                            self.setState({
                                hasMoreItems: false
                            });
                        }
                    })
                    .catch(error => console.log('err ' + error));

        }
    }

    componentDidMount() {
       this.fetchData();
    }

    render() {
    const loader = Loading ...;
    let JobItems; 
    if(this.state.listData){  
        JobItems = this.state.listData.map(Job => {
        return (
            
                {Job.job_number}
                {Job.title}
                {Job.description}
                {Job.status}
            
        );
      });
    }
    return (
      
        
            Jobs List

            
                
                
                    
                        Job Number
                        Title
                        Description
                        Status
                    
                
                
                {JobItems}
                
                
            
        
    
    );
  }

}

export default Jobs;

Похожие вопросы