Бесконечная прокрутка с помощью React JS
Я рассматриваю способы реализации бесконечной прокрутки с помощью React. Я столкнулся с react-infinite-scroll и нашел его неэффективным, поскольку он просто добавляет узлы в DOM и не удаляет их. Есть ли проверенное решение с React, которое будет добавлять, удалять и поддерживать постоянное количество узлов в DOM.
Вот проблема jsfiddle.
В этой проблеме я хочу иметь только 50 элементов в DOM за раз. другие должны быть загружены и удалены, когда пользователь прокручивает вверх и вниз. Мы начали использовать React из-за его алгоритмов оптимизации. Теперь я не мог найти решение этой проблемы. Я столкнулся с airbnb infin 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'));
Поиск помощи...
Ответы
Ответ 1
В основном, при прокрутке вы хотите решить, какие элементы являются видимыми, а затем выполнить рендеринг, чтобы отобразить только эти элементы, с одним элементом распорки сверху и снизу для представления элементов вне экрана.
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
Посетите нашу библиотеку React Infinite:
https://github.com/seatgeek/react-infinite
Обновление декабря 2016 г.
На самом деле, я недавно использовал response-virtualized во многих своих проектах и обнаружил, что он намного лучше покрывает большинство вариантов использования. Обе библиотеки хороши, это зависит именно от того, что вы ищете. Например, response-virtualized поддерживает измерение JIT переменной высоты через HOC с именем CellMeasurer
, пример здесь https://bvaughn.github.io/react-virtualized/#/components/CellMeasurer.
Обновление ноября 2018 года
Многие уроки из реакции-виртуализации были перенесены в меньшую, более быструю и эффективную библиотеку реагирующего окна того же автора.
Ответ 3
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;