Unendliches Scrollen mit React JS


87

Ich suche nach Möglichkeiten, um mit React unendliches Scrollen zu implementieren. Ich bin auf React-Infinite-Scroll gestoßen und fand es ineffizient, da es nur Knoten zum DOM hinzufügt und diese nicht entfernt. Gibt es eine bewährte Lösung mit React, mit der eine konstante Anzahl von Knoten im DOM hinzugefügt, entfernt und beibehalten wird?

Hier ist die jsfiddle Problem. In diesem Problem möchte ich nur 50 Elemente gleichzeitig im DOM haben. andere sollten geladen und entfernt werden, wenn der Benutzer nach oben und unten scrollt. Wir haben begonnen, React aufgrund seiner Optimierungsalgorithmen zu verwenden. Jetzt konnte ich keine Lösung für dieses Problem finden. Ich bin auf Airbnb Infinite Js gestoßen . Aber es wird mit Jquery implementiert. Um diese unendliche Airbnb-Schriftrolle zu verwenden, muss ich die React-Optimierung verlieren, die ich nicht tun möchte.

Beispielcode, den ich hinzufügen möchte, ist scroll (hier lade ich alle Elemente. Mein Ziel ist es, jeweils nur 50 Elemente zu laden).

/** @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'));

Suche nach Hilfe...

Antworten:


56

Grundsätzlich möchten Sie beim Scrollen entscheiden, welche Elemente sichtbar sind, und dann erneut rendern, um nur diese Elemente anzuzeigen, wobei ein einzelnes Abstandselement oben und unten die Offscreen-Elemente darstellt.

Vjeux hat hier eine Geige gemacht, die Sie sich ansehen können: jsfiddle .

Beim Scrollen wird es ausgeführt

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
    });
},

und dann zeigt die Renderfunktion nur die Zeilen im Bereich an displayStart..displayEnd.

Sie könnten auch an ReactJS interessiert sein: Modellierung von bidirektionalem unendlichem Scrollen .


2
Das ist eine großartige Technik ... Danke! Es schlägt jedoch fehl, wenn die recordHeight für jede Zeile unterschiedlich ist. Ich experimentiere mit einer Lösung für diese Situation. Ich werde es posten, wenn ich es zum Laufen bringe.
Manalang

@manalang Haben Sie eine Lösung für unterschiedliche Höhen für jede Reihe gefunden?
Ausnahme

1
Ein weiteres Projekt zum Auschecken ist infinity.js (zur Inspiration). Wenn Sie über dynamische Höhenelemente verfügen, können Sie das Konzept einer "Seite" erstellen, bei der es sich um eine Reihe von Elementen im Ansichtsfenster handelt. Angenommen, es gibt 3 Elemente, und das dritte Element ist super lang und erstreckt sich von der Seite. Dann können Sie beispielsweise sagen, dass "Seitenhöhe" die Größe der drei größten Elemente ist. Erstellen Sie dann virtuelle Knoten mit der kleinsten Elementhöhe. Also var count = pageHeight / minElementHeight. Sie können also 50 Elemente erstellen, obwohl nur 3 gerendert werden, aber das gibt Ihnen trotzdem eine gute Leistung.
Lance Pollard

14
In der Geige erscheint nichts. Schaltflächen zum Generieren werden angezeigt, aber sonst nichts.
Donnerstag,

3
@ sophie-alpert: Ist es möglich, jsfiddle zu aktualisieren? Ich weiß, dass Sie beschäftigt sein werden, aber wenn Sie es aktualisieren können, würde es vielen wie mir zugute kommen: D
John Samuel

26

Schauen Sie sich unsere React Infinite Library an:

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

Update Dezember 2016

Ich habe in letzter Zeit in vielen meiner Projekte React-Virtualized verwendet und festgestellt, dass es die meisten Anwendungsfälle viel besser abdeckt. Beide Bibliotheken sind gut, es kommt genau darauf an, wonach Sie suchen. Zum Beispiel reagieren virtualisierten Unterstützung variabler Höhe JIT Mess über eine HOC genannt CellMeasurer, Beispiel hier https://bvaughn.github.io/react-virtualized/#/components/CellMeasurer .

Update November 2018

Viele der Lehren aus der Reaktiv-Virtualisierung wurden auf die kleineren, schnelleren und effizienteren portiert vom selben Autor React-Window- Bibliothek .


@jos: benutze diese Bibliothek. DOM-Knoten werden entfernt / angehängt, sobald sie im Ansichtsfenster angezeigt werden.
wle8300

14
Diese Bibliothek funktioniert nur, wenn Sie die Höhen Ihrer Elemente vor dem Rendern kennen.
Druska

1
@ Druska, Technisch gesehen ja, aber Sie können das Fenster auch als Bildlaufcontainer mit der Option useWindowAsScrollContainer verwenden.
HussienK

Unterstützt die reaktionsunendliche Bibliothek Gitter?
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;
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.