У меня есть компонентное приложение со списком из реактивно-виртуализированной библиотеки. И мне нужно при первоначальном рендеринге, чтобы мой список прокручивался вниз.
И я сделал это, когда добавил опцию scrollToIndex. Но когда я добавляю новый объект в свой массив списка, он не прокручивается до моего последнего добавленного объекта. Как я могу это исправить? А использование функции forceUpdate () - хорошее решение?
import { List } from "react-virtualized";
import loremIpsum from 'lorem-ipsum';
const rowCount = 1000;
const listHeight = 600;
const rowHeight = 50;
const rowWidth = 800;
class App extends Component {
constructor() {
super();
this.renderRow = this.renderRow.bind(this);
this.list = Array(rowCount).fill().map((val, idx) => {
return {
id: idx,
name: 'John Doe',
image: 'http://via.placeholder.com/40',
text: loremIpsum({
count: 1,
units: 'sentences',
sentenceLowerBound: 4,
sentenceUpperBound: 8
})
}
});
}
handle = () => {
this.list = [...this.list, { id: 1001, name: "haha", image: '', text: 'hahahahahaha' }];
this.forceUpdate();
this.refs.List.scrollToRow(this.list.length);
};
renderRow({ index, key, style }) {
console.info('____________', this.list.length);
return (
<div key = {key} style = {style} className = "row" >
<div className = "image">
<img src = {this.list[index].image} alt = "" />
</div>
<div onClick = {this.handle}>{this.state.a}</div>
<div className = "content">
<div>{this.list[index].name}</div>
<div>{this.list[index].text}</div>
</div>
</div>
);
}
render() {
return (
<div className = "App">
<div className = "list">
<List
ref='List'
width = {rowWidth}
height = {listHeight}
rowHeight = {rowHeight}
rowRenderer = {this.renderRow}
rowCount = {this.list.length}
overscanRowCount = {3}
scrollToIndex = {this.list.length}
/>
</div>
</div>
);
}
}
export default App;





Вы упомянули, что вам нужно прокручивать вниз, когда элемент списка изменяется, и, честно говоря, я не люблю использовать forceUpdate. Как упоминалось в документации React:
Normally you should try to avoid all uses of forceUpdate() and only read from this.props and this.state in render().
К счастью, в этом случае подходит один из методов жизненного цикла React, это вызов componentDidUpdate. Но вам нужно провести некоторый рефакторинг вашего кода. Вместо использования частного поля я предлагаю поместить его в состояние / реквизиты.
Этот метод будет вызываться сразу после обновления свойств / состояния. Однако этот метод не вызывается для первоначального рендеринга.
Что вам нужно сделать, это сравнить реквизит, меняется он или нет? Тогда звоните this.refs.List.scrollToRow(this.list.length);
Образец кода
class App extends Component {
constructor() {
this.state = {
list: [] // put your list data here
}
}
// Check the change of the list, and trigger the scroll
componentDidUpdate(prevProps, prevState) {
const { list } = this.state;
const { list: prevList } = prevState;
if (list.length !== prevList.length) {
this.refs.List.scrollToRow(list.length);
}
}
render() {
// usual business
}
}больше ссылок на методы жизненного цикла React:
https://reactjs.org/docs/react-component.html#componentdidupdate
Да, это лучшая комбинация, если она исходит из состояния редуктора, ее легче отлаживать. Основная проблема, если вы загрузите огромный массив на componentDidMount, это заблокирует поток js и заблокирует некоторую анимацию или взаимодействие. Лучше сделайте разбиение на страницы и загрузите больше элементов, когда достигнете дна, как вы предлагаете.
что нам делать, если мы хотим прокрутить вверх (первая строка) при изменении свойств и / или элемента списка? ScrollToRow позволяет нам прокручивать больше, но что, если мы хотим прокрутить назад?
Спасибо за этот ответ. Будет ли работать, например, если список будет происходить из состояния редуктора? И стоит ли загружать весь мой огромный массив объектов на клиенте из базы данных на componentDidMount? Или лучше загружать части (отправлять запрос на сервер) в прокрутке?