Как прокрутить вниз, когда реквизит изменился в виртуализированной реакции?

У меня есть компонентное приложение со списком из реактивно-виртуализированной библиотеки. И мне нужно при первоначальном рендеринге, чтобы мой список прокручивался вниз.

И я сделал это, когда добавил опцию 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;
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
0
4 080
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы упомянули, что вам нужно прокручивать вниз, когда элемент списка изменяется, и, честно говоря, я не люблю использовать 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? Или лучше загружать части (отправлять запрос на сервер) в прокрутке?

Victor 09.08.2018 18:04

Да, это лучшая комбинация, если она исходит из состояния редуктора, ее легче отлаживать. Основная проблема, если вы загрузите огромный массив на componentDidMount, это заблокирует поток js и заблокирует некоторую анимацию или взаимодействие. Лучше сделайте разбиение на страницы и загрузите больше элементов, когда достигнете дна, как вы предлагаете.

I Putu Yoga Permana 09.08.2018 18:08

что нам делать, если мы хотим прокрутить вверх (первая строка) при изменении свойств и / или элемента списка? ScrollToRow позволяет нам прокручивать больше, но что, если мы хотим прокрутить назад?

benchpresser 24.02.2020 01:25

Другие вопросы по теме