2017-11-25 255 views
0

我正在开发基于react-virtualized的数据网格组件。它应该有一个带有可调整大小列的固定标题。我希望标题根据标题单元格内容更改其高度。我正在使用CellMeasurer来计算单元格高度并更新标题的高度。有没有办法使用react-virtualized来实现动态高度的网格标题?

问题是单元格大小是在单元格呈现后(afaik)计算的,因此如果高度已更改,则必须在标头的render内部调用forceUpdate

这里是如何render样子(完整例子here):

render() { 
    const height = this._cache.rowHeight({ index: 0 }); 
    console.log('render', height, this.props.sizes); 
    setTimeout(() => { 
     if (height !== this._cache.rowHeight({ index: 0 })) { 
     console.log('forceUpdate', this._cache.rowHeight({ index: 0 })) 
     this.forceUpdate() 
     } 
    }, 0) 

    return (
     <Grid 
     ref={ref => this._grid = ref} 
     deferredMeasurementCache={this._cache} 
     width={1500} 
     height={height} 
     columnCount={5} 
     columnWidth={this.columnWidth} 
     rowCount={1} 
     rowHeight={this._cache.rowHeight} 
     cellRenderer={this.renderCell} 
     /> 
    ); 
    } 

所以,问题是如何避免forceUpdate?有没有一种更清晰的方式来使用react-virtualized实现动态高度的网格标题?

回答

0

我觉得我必须张贴它作为一个答案。

布赖恩指出了正确的方向,感谢布赖恩为你的惊人的工作和支持。

onSectionRendered处理是很重要的,因为它让我们更新头部的高度后的第一个渲染:

_onSectionRendered = ({ rowOverscanStartIndex }) => { 
    if (rowOverscanStartIndex === 0) { 
     const height = this._cache.rowHeight({ index: 0 }); 

     if (height !== this.state.headerHeight) { 
     this.setState({ 
      headerHeight: height, 
     }); 
     } 
    } 
    } 

componentWillReceiveProps从原来的codesandbox也是很重要的 - 这是什么使组件上调整的列反应:

componentWillReceiveProps(nextProps) { 
    if (nextProps.sizes !== this.props.sizes) { 
     this._cache.clearAll(); 
     console.log('recomputeGridSize'); 
     this._grid.recomputeGridSize(); 
     console.log('===', this._cache.rowHeight({ index: 0 })) 
    } 
    } 

少了什么是componentDidUpdate

componentDidUpdate() { 
    console.log('componentDidUpdate', 
     this._cache.rowHeight({ index: 0 })); 
    const height = this._cache.rowHeight({ index: 0 }); 

    if (height !== this.state.headerHeight) { 
     this.setState({ 
     headerHeight: height, 
     }); 
    } 
    } 

- 这是我们可以检查行的高度是否与标题的高度不同并在必要时更新它的方法。在初始渲染后不会调用componentDidUpdate,这就是为什么onSectionRendered有帮助。

虽然它不能避免额外的渲染,但它比超时黑客更清洁。 完整的例子是:https://codesandbox.io/s/kor4vv6jqv

1

render中设置超时可能不是一个好主意。

如果单元高度改变(例如从rowHeight返回的值),则CellMeasurer will automatically notify the parent Grid。在这种情况下,Grid will automatically clear its position cache and re-render

你在这个例子中做的不同之处在于将Grid的外部高度设置为等于细胞测量的高度。这不是一个常见的用例,你能支持它不定时黑客就像这样:

class XHeader extends React.Component { 
    _cache = new CellMeasurerCache({ 
    defaultHeight: 20, 
    fixedWidth: true, 
    }); 
    state = { 
    headerHeight: 20, 
    }; 
    renderCell = props => { 
    return (
     <HeaderCell 
     width={this.props.sizes[props.columnIndex]} 
     {...props} 
     cache={this._cache} 
     onMouseDown={this.props.onMouseDown} 
     /> 
    ); 
    } 
    columnWidth = ({ index }) => { 
    return this.props.sizes[index]; 
    } 
    render() { 
    return (
     <Grid 
     ref={ref => this._grid = ref} 
     deferredMeasurementCache={this._cache} 
     width={1500} 
     height={this.state.headerHeight} 
     columnCount={5} 
     columnWidth={this.columnWidth} 
     onSectionRendered={this._onSectionRendered} 
     rowCount={1} 
     rowHeight={this._cache.rowHeight} 
     cellRenderer={this.renderCell} 
     /> 
    ); 
    } 

    _onSectionRendered = ({ rowOverscanStartIndex }) => { 
    if (rowOverscanStartIndex === 0) { 
     const height = this._cache.rowHeight({ index: 0 }); 

     if (height !== this.state.headerHeight) { 
     this.setState({ 
      headerHeight: height, 
     }); 
     } 
    } 
    } 
} 
+0

布赖恩,谢谢你的支持和你的工作!至于答案,这与我试图达成的有点不同,虽然有很大帮助。 –

相关问题