Michiel Borkent
Michiel Borkent

Reputation: 34800

React Virtualized position of list item

I'm using React Virtualized in a similar setup like the snippet below. There are a couple of items that are rendered using a CellMeasurer. The last item indicates that more items will be loaded and is not rendered normally. This item has the wrong position/style and the wrong height associated with it. How can I fix this?

If you want to play with it, here is a Plunkr: https://plnkr.co/edit/TrKdNu4FfNsXqERPVnYo?p=preview

var List = ReactVirtualized.List;
var CellMeasurer = ReactVirtualized.CellMeasurer;
var CellMeasurerCache = ReactVirtualized.CellMeasurerCache;

var cache = new CellMeasurerCache({
  fixedWidth: true,
  minHeight: 50
});

// List data as an array of strings
var namesList = [
  'Brian Vaughn',
  'Bob Smith',
  'Someone Else',
  'I hate making up names for the sake of names.'
  // And so on...
];

var App = React.createClass({
  getInitialState: function() {
    return {
      list: namesList
    };
  },
  render: function() {
    return <List
    className='List'
    width={300}
    height={300}
    rowCount={this.state.list.length + 1}
    rowHeight={cache.rowHeight}
    deferredMeasurementCache={cache}
    list={this.state.list}
    rowRenderer={
      ({ index, isScrolling, key, parent, style }) => {
        var item = this.state.list[index];
        let result;
        if (!item) {
          console.log(index);
          result =
            <div className='Row'
          style={style}
          key={key}
            >Loading!!!
          </div>; }
        else
          result = <CellMeasurer
        cache={cache}
        columnIndex={0}
        key={key}
        style={style}
        rowIndex={index}
        parent={parent}>
          {

              <div
            className='Row'
            key={key}
            style={style}
              >
              {this.state.list[index]}
            </div>
          }
        </CellMeasurer>;
        return result;
      }}/>;
  }
});

// Render your list
ReactDOM.render(
  <App/>,
  document.getElementById('example')
);
.List {
  border: 1px solid black;
  box-sizing: border-box;
}
.Row {
  width: 100%;
  height: 100%;
  border-bottom: 1px solid black;
  display: flex;
  align-items: center;
  padding: 0 0.5rem;
  box-sizing: border-box;
}
<!DOCTYPE html>
<html>
  <head>
    <script src="https://unpkg.com/react/dist/react-with-addons.min.js"></script>
    <script src="https://unpkg.com/react-dom/dist/react-dom.min.js"></script>
    <script src="https://unpkg.com/react-virtualized/dist/umd/react-virtualized.js"></script>

    <link rel="stylesheet" href="https://unpkg.com/react-virtualized/styles.css">
    <link rel="stylesheet" href="styles.css">
  </head>

  <body>
    <div id="example">
      <!-- This element's contents will be replaced with your code... -->
    </div>
    <script src="script.js"></script>
  </body>

</html>

Upvotes: 0

Views: 3089

Answers (1)

bvaughn
bvaughn

Reputation: 13487

CellMeasurer wasn't intended for use with only certain rows in this way. From an external POV I understand why it looks like it should just work though.

When Grid renders a cell- if it thinks CellMeasurer is being used- then it positions the cell at top:0, left:0 to give it space within the Grid/List to expand. (The size of its container constrains its size, even though it's absolutely positioned. I'm not sure why this is to be honest.)

So in your case, Grid sees the last row hasn't been measured, think it's supposed to be, and positions it at 0,0.

The simplest solution for now would be to just wrap that row in CellMeasurer too.

Upvotes: 2

Related Questions