Нескінченна прокрутка за допомогою React JS


89

Я шукаю шляхи реалізації нескінченної прокрутки за допомогою React. Я зіткнувся з response-infinite-scroll і виявив його неефективним, оскільки він просто додає вузли до DOM і не видаляє їх. Чи існує якесь перевірене рішення з React, яке додасть, видалить та підтримує постійну кількість вузлів у DOM.

Ось проблема jsfiddle . У цій проблемі я хочу мати лише 50 елементів у DOM одночасно. інші слід завантажувати та видаляти, коли користувач прокручує вгору та вниз. Ми почали використовувати React через його алгоритми оптимізації. Тепер я не міг знайти рішення цієї проблеми. Я зіткнувся з airbnb нескінченним js . Але це реалізовано за допомогою Jquery. Щоб використовувати цю нескінченну прокрутку airbnb, я повинен втратити оптимізацію React, яку я не хочу робити.

зразок коду, який я хочу додати, є сувій (тут я завантажую всі елементи. Моя мета - завантажувати лише 50 елементів одночасно)

/** @jsx React.DOM */

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

var HelloList = React.createClass({ 
     getInitialState: function() {                            
         var numbers =  [];
         for(var i=1;i<10000;i++){
             numbers.push(i);
         }
         return {data:numbers};
     },

    render: function(){
       var response =  this.state.data.map(function(contact){          
          return (<Hello name="World"></Hello>);
        });

        return (<ul>{response}</ul>)
    }
});

React.renderComponent(<HelloList/>, document.getElementById('content'));

Шукаю допомогу ...

Відповіді:


57

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

Тут Vjeux зробив скрипку, на яку ви можете подивитися: jsfiddle .

Після прокрутки він виконується

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: Моделювання двонаправленої нескінченної прокрутки .


2
Це чудова техніка ... thx! Однак це не вдається, коли записHeight відрізняється для кожного рядка. Я експериментую з виправленням цієї ситуації. Опублікую, якщо змушу працювати.
manalang

@manalang Ви знайшли рішення для різної висоти для кожного рядка?
Виняток

1
Ще один проект, який потрібно перевірити, - infinity.js (для натхнення). Якщо у вас є динамічні елементи висоти, ви можете створити концепцію "сторінки", яка є набором елементів у вікні перегляду. Скажімо, є 3 елементи, а третій елемент надзвичайно довгий і тягнеться від сторінки. Тоді ви можете, скажімо, "висота сторінки" - це розмір найбільших 3 елементів. Потім побудуйте віртуальні вузли, використовуючи найменшу висоту елемента. Отже var count = pageHeight / minElementHeight. Отже, ви можете побудувати 50 елементів, хоча відображаються лише 3, але це все одно забезпечить вам хорошу продуктивність.
Lance Pollard

14
У скрипці нічого не з’являється. З'являються кнопки генерації, але нічого іншого.
удар

3
@ sophie-alpert: Чи можна оновити jsfiddle? Я знаю, що ти будеш зайнятий, але якщо ти зможеш його оновити, це виграє багатьом, як я: D
Джон Семюел

26

Перегляньте нашу бібліотеку React Infinite:

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

Оновлення в грудні 2016 року

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

Оновлення листопада 2018 р

Багато уроків з реагування на віртуалізацію було перенесено на меншу, швидшу та ефективнішу бібліотеку вікна реагування від того самого автора.


@jos: використовуйте цю бібліотеку. Він видалить / додасть вузли DOM у міру їх появи у вікні перегляду.
wle8300

14
Ця бібліотека працює лише в тому випадку, якщо ви знаєте висоту своїх елементів перед відтворенням.
Друська

1
@Druska, Технічно так, однак ви також можете використовувати вікно як контейнер прокрутки, використовуючи опцію useWindowAsScrollContainer.
HussienK

Чи підтримує безмежно реагуюча бібліотека сітки?
user1261710


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 = <div className="loader">Loading ...</div>;
    let JobItems; 
    if(this.state.listData){  
        JobItems = this.state.listData.map(Job => {
        return (
            <tr>
                <td>{Job.job_number}</td>
                <td>{Job.title}</td>
                <td>{Job.description}</td>
                <td>{Job.status}</td>
            </tr>
        );
      });
    }
    return (
      <div className="Jobs">
        <div className="container">
            <h2>Jobs List</h2>

            <InfiniteScroll
                pageStart={0}
                loadMore={this.fetchData.bind(this)}
                hasMore={this.state.hasMoreItems}
                loader={loader}>
                <table className="table table-bordered">
                <thead>
                    <tr>
                        <th>Job Number</th>
                        <th>Title</th>
                        <th>Description</th>
                        <th>Status</th>
                    </tr>
                </thead>
                <tbody>
                {JobItems}
                </tbody>
                </table>
            </InfiniteScroll>
        </div>
    </div>
    );
  }

}

export default Jobs;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.