【问题标题】:How to set up dynamic row height in react-virtualized List?如何在反应虚拟化列表中设置动态行高?
【发布时间】:2017-05-15 03:14:21
【问题描述】:

我在 StackOverflow 上查看了很多答案。我也在这里查看了列表文档,react-virtualized/List。但是,我仍然无法理解如何在 react-virtualized 列表中动态设置行高。 rowHeight prop 函数中的高度如何计算?

我可以像rowHeight={({ index }) => this.computeRowHeight({ index })} 这样调用我的函数。但是该函数将如何计算行高?

以下是代码供参考。

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { AutoSizer, InfiniteLoader, List } from 'react-virtualized';
import _ from 'lodash';

class InfiniteList extends Component {
  constructor(props) {
    super(props);
    this.state = {
      list: props.list,
      loading: false
    };
  }
  componentDidMount() {
    fetch('http://jsonplaceholder.typicode.com/comments')
      .then((response) => {
        response.json().then((data) => {
          this.setState({
            list: _.concat(this.state.list, _.map(data, 'body')),
            loading: false
          });
        });
      });
  }
  isRowLoaded({ index }) {
    return !!this.state.list[index];
  }

  loadMoreRows({ startIndex, stopIndex }) {
    if (this.state.loading) {
      return;
    }
    this.setState({
      loading: true
    });
    return fetch('http://jsonplaceholder.typicode.com/comments')
      .then((response) => {
        response.json().then((data) => {
          // Simulate delay
          setTimeout(() => {
            this.setState({
              list: _.concat(this.state.list, _.map(data, 'body')),
              loading: false
            });
          }, 3000);
        });
      });
  }

  rowRenderer({ key, index, isScrolling, isVisible, style }) {
    if (isVisible) {
      return (
        <div key={key}>
          <div style={style}>#{this.state.list[index]}.</div>
        </div>
      );
    }
  }

  render() {
    return (
      <div>
        <InfiniteLoader
          isRowLoaded={({ index }) => this.isRowLoaded({ index })}
          loadMoreRows={({ startIndex, stopIndex }) => this.loadMoreRows({ startIndex, stopIndex })}
          rowCount={this.state.list.length}
        >
          {({ onRowsRendered, registerChild }) => (
            <AutoSizer disableHeight>
              {({ width }) => (
                <List
                  onRowsRendered={onRowsRendered}
                  ref={registerChild}
                  width={width}
                  height={320}
                  rowCount={this.state.list.length}
                  rowHeight={40}
                  rowRenderer={({ key, index, isScrolling, isVisible, style }) => this.rowRenderer({ key, index, isScrolling, isVisible, style })}
                />
              )}
            </AutoSizer>
          )}
        </InfiniteLoader>
        {this.state.loading && <p>Loading...</p>}
      </div>
    );
  }
}

const list = [];

ReactDOM.render(
  <InfiniteList list={list} />,
  document.querySelector('#root')
);

更新

动态高度现在与CellMeasurer 一起使用以下代码。但是,不幸的是this.loadMoreRows() 函数没有在InfiniteLoader 中调用。没有CellMeasurer 也无法正常工作。我不确定我在下面的代码中做错了什么。

import React, { Component } from 'react';
import { AutoSizer, CellMeasurer, InfiniteLoader, List } from 'react-virtualized';
import _ from 'lodash';

class InfiniteList extends Component {
  constructor(props) {
    super(props);
    this.state = {
      list: props.list,
      loading: false
    };
  }
  componentDidMount() {
    fetch('http://jsonplaceholder.typicode.com/comments')
      .then((response) => {
        response.json().then((data) => {
          this.setState({
            list: _.concat(this.state.list, _.map(data, 'body')),
            loading: false
          });
        });
      });
  }
  isRowLoaded({ index }) {
    return !!this.state.list[index];
  }

  loadMoreRows({ startIndex, stopIndex }) {
    if (this.state.loading) {
      return;
    }
    this.setState({
      loading: true
    });
    return fetch('http://jsonplaceholder.typicode.com/comments')
      .then((response) => {
        response.json().then((data) => {
          // Simulate delay
          setTimeout(() => {
            this.setState({
              list: _.concat(this.state.list, _.map(data, 'body')),
              loading: false
            });
          }, 3000);
        });
      });
  }

  rowRenderer({ key, index, isScrolling, isVisible, style }) {
    if (isVisible) {
      return (
        <div key={key} style={style}>#{index} {this.state.list[index]}.</div>
      );
    }
  }
  cellRenderer({ columnIndex, key, rowIndex, style }) {
    return (
      <div
        key={key}
        style={style}
      >
        <div>#{rowIndex} {this.state.list[rowIndex]}.</div>
      </div>
    );
  }
  render() {
    return (
      <div>
        <InfiniteLoader
          isRowLoaded={isRowLoaded => this.isRowLoaded(isRowLoaded)}
          loadMoreRows={loadMoreRows => this.loadMoreRows(loadMoreRows)}
          rowCount={this.state.list.length}
        >
          {({ onRowsRendered, registerChild }) => (
            <AutoSizer disableHeight>
              {({ width }) => (
                <CellMeasurer
                  cellRenderer={cellRenderer => this.cellRenderer(cellRenderer)}
                  columnCount={1}
                  rowCount={this.state.list.length}
                >
                  {({ getRowHeight }) => (
                    <List
                      onRowsRendered={onRowsRendered}
                      ref={registerChild}
                      width={width}
                      height={400}
                      rowCount={this.state.list.length}
                      rowHeight={getRowHeight}
                      rowRenderer={rowRenderer => this.rowRenderer(rowRenderer)}
                    />
                  )}
                </CellMeasurer>
              )}
            </AutoSizer>
          )}
        </InfiniteLoader>
        {this.state.loading && <p>Loading...</p>}
      </div>
    );
  }
}

const list = [];

ReactDOM.render(
  <InfiniteList list={list} />,
  document.querySelector('#root')
);

任何帮助将不胜感激。谢谢!

【问题讨论】:

    标签: reactjs react-virtualized


    【解决方案1】:

    我经历了你和其他人提到的所有事情,最后,我最终创建了这个Example,我也解释了here。它在react hooks 旁边使用Table,这可能对其他人也有帮助。我为一些可能有一些可扩展行的表构建了这个。

    【讨论】:

      【解决方案2】:

      你需要自己写computeRowHeight来确定行高。在某些情况下,根据该行的索引和属性,您可能能够知道该行的高度。例如,如果您的行可能是不同的组件,如果您知道某行将是高度为 40 的组件 A,而另一行将是高度为 60 的组件 B,您可以检查这些道具并返回正确的高度。

      如果您不知道高度,那么您将不得不实际查看 DOM 中的元素并找出它的高度。如果它在 DOM 中尚不存在,则需要最初返回一个最佳猜测,然后在渲染后调用 recomputeRowHeights 并检查 DOM。

      【讨论】:

      • 添加到 Drew 的回答中,如果您对内容的大小一无所知,您可能想要使用另一个反应虚拟化组件,例如 CellMeasurer。我还听说有人使用 react-measure 和 react-virtualized 效果很好。
      • @brianvaughn 谢谢!以前我无法使用 CellMeasurer 获得动态高度。但是,我再次尝试了它,现在它正在工作(尽管有时几行重叠)。但是,不幸的是,我的 this.loadMoreRows() 函数没有在 InfiniteLoader 中被调用。我认为它在 CellMeasurer 之前也不起作用。所以它与 CellMeasurer 无关。我不确定我在这里做错了什么。感谢您的宝贵时间!
      • 我想通了。我必须在rowCount 中给InfiniteLoader 中的任意高数字而不是rowCount={this.state.list.length}
      • 有人碰巧有一个几年后的例子吗?
      猜你喜欢
      • 2019-06-12
      • 2017-01-28
      • 2017-08-20
      • 2017-10-05
      • 1970-01-01
      • 2018-01-03
      • 2017-07-13
      • 2021-05-25
      • 1970-01-01
      相关资源
      最近更新 更多