Infini défilement à l'aide de Réagir JS

je cherche des moyens de mettre en œuvre infinite scrolling avec React. Je suis tombé sur react-infinite-scroll et je l'ai trouvé inefficace car il ajoute juste des noeuds au DOM et ne les enlève pas. Existe-t-il une solution éprouvée avec React qui ajoutera, supprimera et maintiendra un nombre constant de noeuds dans le DOM.

voici le problème jsfiddle . Dans ce problème, je veux avoir seulement 50 éléments dans le DOM à la fois. les autres doivent être chargés et supprimés au fur et à mesure que l'utilisateur monte et descend. Nous avons commencé à utiliser Réagir à cause d'algorithmes d'optimisation. Maintenant, je ne pouvais pas trouver de solution à ce problème. J'ai rencontré airbnb infinite js . Mais il est mis en œuvre avec Jquery. Pour utiliser cet Airbnb infinite scroll, je dois perdre L'optimisation React que je ne veux pas faire.

exemple de code que je veux ajouter de défilement est(ici je suis le chargement de tous les éléments. Mon but est de charger seulement 50 articles à la fois)

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

cherche de l'aide...

67
demandé sur Trinh Hoang Nhu 2014-01-20 20:04:51

4 réponses

en fait, lorsque vous faites défiler, vous voulez décider quels éléments sont visibles, et ensuite choisir de n'afficher que ces éléments, avec un seul élément d'espacement en haut et en bas pour représenter les éléments hors écran.

Vjeux fait un violon ici que vous pouvez regarder:

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

lors du défilement il exécute

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

et alors la fonction de rendu affichera seulement les lignes dans la gamme displayStart..displayEnd .

Vous pourriez également être intéressé par ReactJS: Modélisation Bi-Directionnelle Infini Défilement .

50
répondu Sophie Alpert 2017-05-23 11:55:02

regardez notre Libaire React Infinite:

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

Mise À Jour Décembre 2016

j'ai effectivement utilisé react-virtualized dans beaucoup de mes projets récemment et trouver qu'il couvre la majorité des cas d'utilisation beaucoup mieux. Les deux bibliothèques sont bonnes, cela dépend exactement ce que vous cherchez. Pour exemple, react-virtualized supporte des JIT de hauteur variable mesurant via un HOC appelé CellMeasurer , exemple ici https://bvaughn.github.io/react-virtualized/#/components/CellMeasurer .

17
répondu Zach 2016-12-10 23:56:07

Infinite Scroll Concept À L'Aide De Réagir Js


nous pouvons faire un travail infini de défilement en écoutant l'événement de défilement. Nous pouvons ajouter un écouteur d'événement soit au parent le plus div ou même à l'objet window.

regardez le code suivant

   render() {
        return (
          <div
            className="vc"
            ref="iScroll"
            style={{ height: "420px", overflow: "auto" }}
          >
            <h2>Hurrah! My First React Infinite Scroll</h2>
            <ul>

            </ul>
          </div>
        );
    }

le code ci-dessus a une étiquette ul simple; à l'intérieur de laquelle nous lierons les éléments récupérés. Cette étiquette est entourée par un div sur laquelle nous allons nous attacher un écouteur d'événement pour écouter l'événement scroll.

j'espère que vous êtes au courant de toutes les étiquettes utilisées ici. N'est-ce pas? Certains d'entre vous ne sont peut-être pas familiers avec l'arbitre! Donc, ref est utilisé pour définir la référence à la division (div) ou tout autre élément html. En utilisant cette référence vous pouvez obtenir une prise sur cet élément de réagir. Nous avons donné à la référence un nom "iScroll" et vous pouvez accéder à cette div en utilisant ceci.réf.iScroll.

assurez-vous que la hauteur du div est inférieure à la hauteur totale des éléments primaires affichage sinon vous n'obtiendrez pas la barre déroulement. Vous pouvez définir la hauteur à 100% ou utiliser l'objet window à la place de notre div iScroll pour faire le scroll au niveau de la fenêtre.

parlons maintenant du constructeur qui ressemblera à ceci:

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

il y a deux propriétés dans l'objet d'état ici; items and loadingState. Les articles signifient le nombre de les éléments disponibles qui peuvent être inclus comme lis dans la section ul et l'état de chargement a été utilisé pour afficher un chargement de texte... lorsque les données sont chargées. Comme nous fournissons juste une démo, c'est pourquoi utilisé un nombre comme éléments. Dans l'application réelle vous tiendrez probablement votre liste réelle de données là.

après cela, vous créerez une fonction qui affichera tous les éléments:

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

cette fonction crée une liste de li et affiche tous les article. Encore une fois, comme c'est une démo, nous affichons en utilisant le numéro. Dans les applications réelles, vous devez itérer sur votre tableau d'articles et afficher les valeurs qu'il contient.

mettre à jour la fonction de rendu maintenant:

render() {
    return (
      <div
        className="vc"
        ref="iScroll"
        style={{ height: "200px", overflow: "auto" }}
      >
        <h2>Hurrah! My First React Infinite Scroll</h2>
        <ul>
          {this.displayItems()}
        </ul>
        {this.state.loadingState
          ? <p className="loading">
          loading More Items..
        </p>
          : ""}
      </div>
    );
} 

Oui, c'est juste un composant normal montrant peu de lis. Comment rendre à l'infini défilement? J'espère que vous vous souvenez que nous avons utilisé un arbitre nommé iScroll plus tôt, cela entre en action maintenant.

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

Comme vous le savez tous react components a une fonction componentDidMount () qui est appelée automatiquement lorsque le modèle de ce component est rendu dans le DOM. Et j'ai utilisé la même fonction pour ajouter l'écouteur d'événement pour défiler dans notre div iScroll. La propriété scrollTop de l'élément va trouver la position de défilement et il avec la propriété clientHeight. Ensuite, la condition if vérifiera que l'addition de ces deux propriétés est supérieure ou égale à la hauteur de la barre de défilement ou non. Si la condition est vraie la fonction loadMoreItems s'exécute.

voici à quoi ressemblera la fonction:

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

c'est assez simple, d'abord définir l'état de chargement à true et le div de chargement sera affiché (comme indiqué dans la fonction de rendu). Ensuite, une fonction setTimeout est appelée qui augmentera le nombre d'items de 10 et rendra à nouveau l'état de chargement false. Ici, la raison pour laquelle nous utilisons setTimeout est de générer un délai. Dans les applications réelles, vous probablement faire un appel ajax sur votre serveur et sur la résolution de faire une chose semblable qui est fait par le rappel de notre setTimeout. Code complet snippet ici:

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(<li key={i}>Item {i}</li>);
    }
    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 (
      <div ref="iScroll" style={{ height: "200px", overflow: "auto" }}>
        <ul>
          {this.displayItems()}
        </ul>

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

      </div>
    );
  }
}

ReactDOM.render(<Layout />, document.getElementById('example'));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="example"></div>
10
répondu Aniket Jha 2018-04-12 09:16:42
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;
1
répondu Sneh 2018-04-11 08:16:21