texas697
texas697

Reputation: 6397

How to use react-virtualized with dynamic list height

I am trying to implement react-virtualized into my project. I have a side panel with a list of subdivisions. I would like to have an accordion-like functionality when the user selects an item. When the page first loads it looks like it is working correctly.

screenshot

However when I start to scroll down the list looks like this

screenshot2

and here is code

const mapStateToProps = state => ({
  windowHeight: state.dimensions.windowHeight,
  sbds: new Immutable.List(state.sbds.data),
  sbd: state.sbd.data
})

@connect(mapStateToProps)
export default class SBD extends Component {
  static propTypes = {
    windowHeight: PropTypes.number,
    sbds: PropTypes.instanceOf(Immutable.List),
    sbd: PropTypes.object
  }

  constructor(props) {
    super(props)
    this.state = {
      listHeight: props.windowHeight - 250,
      listRowHeight: 60,
      overscanRowCount: 10,
      rowCount: props.sbds.size,
      scrollToIndex: undefined,
      collapse: true
    }
  }

  componentWillUnmount() {
  }

  shouldComponentUpdate(nextProps, nextState) {
    const {sbds} = this.props
    if (shallowCompare(this, nextProps, nextState))
      return true
    else return stringify(sbds) !== stringify(nextProps.sbds)
  }

  _handleSelectRow = selected => {
    sbdRequest(selected)
    const obj = {[selected.id]: true}
    this.setState(obj)
  }

  render() {
    const {
      listHeight,
      listRowHeight,
      overscanRowCount,
      rowCount,
      scrollToIndex
    } = this.state

    return (
      <div>
        <SearchGroup />
        <Card className='border-0 mt-10 mb-0'>
          <CardBlock className='p-0'>
            <AutoSizer disableHeight>
              {({width}) => (
                <List
                  ref='List'
                  className=''
                  height={listHeight}
                  overscanRowCount={overscanRowCount}
                  rowCount={rowCount}
                  rowHeight={listRowHeight}
                  rowRenderer={this._rowRenderer}
                  scrollToIndex={scrollToIndex}
                  width={width}
                />
              )}
            </AutoSizer>
          </CardBlock>
        </Card>
      </div>
    )
  }

  _getDatum = index => {
    const {sbds} = this.props
    return sbds.get(index % sbds.size)
  }

  _rowRenderer = ({index}) => {
    const {sbd} = this.props
    const datum = this._getDatum(index)
    return (
      <span key={datum.id}>
        <Button
          type='button'
          color='link'
          block
          onClick={() => this._handleSelectRow(datum)}>
          {datum.name}
        </Button>
        <Collapse isOpen={this.state[datum.id]}>
          <Card>
            <CardBlock>
            FOO BAR
            </CardBlock>
          </Card>
        </Collapse>
      </span>
    )
  }
}

Upvotes: 1

Views: 2344

Answers (1)

bvaughn
bvaughn

Reputation: 13487

You're not setting the style parameter (passed to your rowRenderer). This is the thing that absolutely positions rows. Without it, they'll all stack up in the top/left as you scroll.

https://bvaughn.github.io/forward-js-2017/#/32/1

Upvotes: 2

Related Questions