2017-11-25 257 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

布賴恩,謝謝你的支持和你的工作!至於答案,這與我試圖達成的有點不同,雖然有很大幫助。 –

相關問題