javascript - script - Desplazamiento infinito con React JS
react helmet ssr (4)
Básicamente, al desplazarse, desea decidir qué elementos son visibles y luego volver a mostrarlos para mostrar solo esos elementos, con un solo elemento espaciador en la parte superior e inferior para representar los elementos fuera de pantalla.
Vjeux hizo un violín aquí que puedes ver:
http://jsfiddle.net/vjeux/KbWJ2/9/
Al desplazarse, se ejecuta
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
});
},
y luego la función de renderizado solo mostrará las filas en el rango displayStart..displayEnd
.
También puede interesarle ReactJS: Modelado de Desplazamiento Infinito Bidireccional .
Estoy buscando formas de implementar el desplazamiento infinito con React. Me encontré con react-infinite-scroll y lo encontré ineficiente, ya que solo agrega nodos al DOM y no los elimina. ¿Hay alguna solución probada con React que agregará, eliminará y mantendrá un número constante de nodos en el DOM.
Aquí está el problema jsfiddle . En este problema, quiero tener solo 50 elementos en el DOM a la vez. otros deben cargarse y eliminarse a medida que el usuario se desplaza hacia arriba y hacia abajo. Hemos comenzado a usar React debido a sus algoritmos de optimización. Ahora no podría encontrar una solución a este problema. Me he encontrado con airbnb infinite js . Pero está implementado con Jquery. Para usar este scroll infinito de Airbnb, tengo que perder la optimización de React que no quiero hacer.
El código de muestra que quiero agregar es scroll (aquí estoy cargando todos los artículos. Mi objetivo es cargar solo 50 elementos a la vez)
/** @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''));
En busca de ayuda...
Eche un vistazo a nuestra Biblioteca Reaccionar Infinita:
https://github.com/seatgeek/react-infinite
Actualización diciembre de 2016
De hecho, he estado usando react-virtualized en muchos de mis proyectos recientemente y encuentro que cubre la mayoría de los casos de uso mucho mejor. Ambas bibliotecas son buenas, depende exactamente de lo que estás buscando. Por ejemplo, react-virtualized admite la medición JIT de altura variable a través de un HOC llamado CellMeasurer
, ejemplo aquí https://bvaughn.github.io/react-virtualized/#/components/CellMeasurer .
Concepto de desplazamiento infinito con React Js
Podemos hacer que el desplazamiento infinito funcione escuchando el evento scroll. Podemos agregar un detector de eventos al div principal o incluso al objeto de ventana.
Eche un vistazo al siguiente código
render() {
return (
<div
className="vc"
ref="iScroll"
style={{ height: "420px", overflow: "auto" }}
>
<h2>Hurrah! My First React Infinite Scroll</h2>
<ul>
</ul>
</div>
);
}
El código anterior tiene una etiqueta ul simple; dentro del cual uniremos los elementos obtenidos. Esta etiqueta está rodeada por un div en el que vamos a adjuntar un detector de eventos para escuchar el evento de desplazamiento.
Espero que conozcas todas las etiquetas usadas aquí. ¿No es así? Bueno, algunos de ustedes pueden no estar familiarizados con ref! Entonces, ref se usa para definir la referencia a la división (div) o cualquier otro elemento html. Al usar esta referencia, puedes atrapar ese elemento en reaccionar. Le hemos dado a la referencia el nombre "iScroll" y puede acceder a este div usando this.refs.iScroll.
Asegúrate de que la altura del div sea menor que la altura total del elemento primario que muestra los elementos, de lo contrario no obtendrás la barra de desplazamiento. Puede establecer la altura al 100% o usar el objeto de la ventana en lugar de nuestro div de iScroll para hacer que el desplazamiento en el nivel de la ventana.
Ahora hablemos del constructor que se verá así:
constructor(props) {
super(props);
this.state = {
items: 10,
loadingState: false
};
}
Aquí hay dos propiedades en el objeto de estado; artículos y loadingState. Los elementos indican la cantidad de elementos disponibles que se pueden incluir como lis dentro de la sección ul y el estado de carga se ha usado para mostrar una carga de texto ... cuando se cargan datos. Como solo ofrecemos una demostración, es por eso que usamos un número como elementos. En aplicaciones reales, probablemente mantendrá allí su lista real de datos.
Después de eso, creará una función que representará todos los elementos:
displayItems() {
var items = [];
for (var k = 0; k < this.state.items; k++) {
items.push(<li key={k}>Item-VoidCanvas {k}</li>);
}
return items;
}
Esta función crea una lista de li y muestra todos los elementos. De nuevo, como es una demostración, estamos mostrando el número. En aplicaciones reales necesita iterar en su matriz de elementos y mostrar los valores que contiene.
Actualice la función de renderizado ahora:
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>
);
}
Sí, esto es solo un componente normal que muestra pocas lis. ¿Cómo lo hace infinitamente desplazable? Espero que recuerdes que hemos usado una referencia llamada iScroll anteriormente, esto entra en acción ahora.
componentDidMount() {
this.refs.iScroll.addEventListener("scroll", () => {
if (
this.refs.iScroll.scrollTop + this.refs.iScroll.clientHeight >=
this.refs.iScroll.scrollHeight
) {
this.loadMoreItems();
}
});
}
Como todos saben, reaccionar componentes tiene una función componentDidMount () que se llama automáticamente cuando la plantilla de ese componente se representa en el DOM. Y he usado la misma función para agregar el detector de eventos para desplazarse a nuestro div iScroll. La propiedad scrollTop del elemento encontrará la posición de desplazamiento y la propiedad clientHeight. A continuación, la condición if verificará si la adición de estas dos propiedades es mayor o igual a la altura de la barra de desplazamiento o no. Si la condición es verdadera, se ejecutará la función loadMoreItems.
Así es como se verá la función:
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);
}
Es bastante simple, primero configure el estado de carga en verdadero y se mostrará el div de carga (como se muestra en la función de renderizado). A continuación, se llama a una función setTimeout que aumentará el número de elementos en 10 y volverá a falsear el estado de carga. Aquí el motivo por el que estamos utilizando setTimeout es generar un retraso de tiempo. En aplicaciones reales, probablemente haga una llamada ajax a su servidor y en la resolución de eso realizará algo similar que se realiza mediante la devolución de llamada de nuestro setTimeout. Fragmento de código completo aquí:
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>
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;