有没有办法使用 react-virtualized 实现具有动态高度的网格 header?
Is there a way to implement grid header with dynamic height using react-virtualized?
我正在开发一个基于 react-virtualized 的数据网格组件。它应该有一个固定的 header 和可调整大小的列。我希望 header 根据 header 单元格内容更改其高度。我正在使用 CellMeasurer 来计算 header 的单元格高度和更新高度。
问题是单元格大小是在渲染单元格后计算的 (afaik),所以如果高度有,我必须在 header 的 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 实现具有动态高度的网格 header?
在 render
中设置超时可能不是一个好主意。
如果单元格的高度发生变化(例如 rowHeight
返回的值),则 CellMeasurer
will automatically notify the parent Grid
. In that case, 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,
});
}
}
}
}
我觉得我必须post它作为答案。
Brian 指出了正确的方向,感谢 Brian 的出色工作和支持。
那个 onSectionRendered
处理程序很重要,因为它让我们在第一次渲染后更新 header 的高度:
_onSectionRendered = ({ rowOverscanStartIndex }) => {
if (rowOverscanStartIndex === 0) {
const height = this._cache.rowHeight({ index: 0 });
if (height !== this.state.headerHeight) {
this.setState({
headerHeight: height,
});
}
}
}
来自原始 codesandbox 的 componentWillReceiveProps
也很重要——它使组件对列大小调整做出反应:
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,
});
}
}
-- 这是我们可以检查行的高度是否不同于 header 的高度并在必要时更新它的方法。 componentDidUpdate
不会在初始渲染后调用,这就是 onSectionRendered
有用的原因。
虽然它没有避免额外的渲染,但它比超时 hack 更干净。
完整的例子在这里:https://codesandbox.io/s/kor4vv6jqv。
我正在开发一个基于 react-virtualized 的数据网格组件。它应该有一个固定的 header 和可调整大小的列。我希望 header 根据 header 单元格内容更改其高度。我正在使用 CellMeasurer 来计算 header 的单元格高度和更新高度。
问题是单元格大小是在渲染单元格后计算的 (afaik),所以如果高度有,我必须在 header 的 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 实现具有动态高度的网格 header?
在 render
中设置超时可能不是一个好主意。
如果单元格的高度发生变化(例如 rowHeight
返回的值),则 CellMeasurer
will automatically notify the parent Grid
. In that case, 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,
});
}
}
}
}
我觉得我必须post它作为答案。
Brian 指出了正确的方向,感谢 Brian 的出色工作和支持。
那个 onSectionRendered
处理程序很重要,因为它让我们在第一次渲染后更新 header 的高度:
_onSectionRendered = ({ rowOverscanStartIndex }) => {
if (rowOverscanStartIndex === 0) {
const height = this._cache.rowHeight({ index: 0 });
if (height !== this.state.headerHeight) {
this.setState({
headerHeight: height,
});
}
}
}
来自原始 codesandbox 的 componentWillReceiveProps
也很重要——它使组件对列大小调整做出反应:
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,
});
}
}
-- 这是我们可以检查行的高度是否不同于 header 的高度并在必要时更新它的方法。 componentDidUpdate
不会在初始渲染后调用,这就是 onSectionRendered
有用的原因。
虽然它没有避免额外的渲染,但它比超时 hack 更干净。 完整的例子在这里:https://codesandbox.io/s/kor4vv6jqv。