使用动态高度List时元素重叠
Overlap of elements when using dynamic height List
我在呈现 Feed 时遇到了与 Facebook 几乎相同的问题。一渲染很多post,性能问题就出现了。经过一些研究后,我发现了 react-virtualized,这很棒,但我很难让它适用于我的应用程序。
这些是我面临的问题:
- 由于每个 post 都可以嵌入 iframe 或图像,所以一旦这些项目加载完毕,我就会从
CellMeasurer
触发 measure
回调。因此,有些项目似乎错位。每次调用 measure
回调时,我都尝试执行 parent.measureAllRows()
和 parent.recomputeRowHeights()
以查看它是否会修复它,但它没有。
- 每个 post 都有一个可展开的部分,因此我需要重新计算它的高度。除了将道具发送到组件之外,还有其他选择吗?
这是设置:
class VirtualPostList extends React.PureComponent {
constructor(props, context) {
super(props, context);
this._cache = new ReactVirtualized.CellMeasurerCache({
fixedWidth: true,
defaultHeight: 400
});
this.rowRenderer = this.rowRenderer.bind(this);
}
rowRenderer({index, isScrolling, key, parent, style}) {
return (
<ReactVirtualized.CellMeasurer
cache={this._cache}
columnIndex={0}
key={key}
parent={parent}
rowIndex={index}>
{({measure}) => (
<div key={key} style={style}>
<Post onLoad={measure}/>
</div>
)}
</ReactVirtualized.CellMeasurer>
)
}
componentDidUpdate(){
this.listComponent.recomputeRowHeights();
}
render() {
const cache = this._cache;
const rowCount = this.props.posts.length;
const _this = this;
return (
<ReactVirtualized.WindowScroller>
{({height, isScrolling, onChildScroll, scrollTop}) =>
<ReactVirtualized.AutoSizer disableHeight>
{({width}) =>
<ReactVirtualized.List
autoHeight
isScrolling={isScrolling}
height={height}
width={width}
rowCount={rowCount}
deferredMeasurementCache={cache}
rowHeight={cache.rowHeight}
rowRenderer={this.rowRenderer}
scrollTop={scrollTop}
onScroll={onChildScroll}
ref={(listComponent) => _this.listComponent = listComponent}
/>
}
</ReactVirtualized.AutoSizer>}
</ReactVirtualized.WindowScroller>
)
}
}
重叠示例:
正如@brianvaughn 所建议的,我并没有在每个应该调用的地方调用 measure
方法。这些变得有点样板并且难以维护,因为元素不仅有图像,而且它们可以自行扩展或收缩。
因为我想避免手动调用 measure
,所以我将 ResizeObserver 附加到组件,就像 ReactMeasure
一样。之后,我将 rowRenderer
函数更改为:
rowRenderer({index, isScrolling, key, parent, style}) {
return (
<ReactVirtualized.CellMeasurer
cache={this._cache}
columnIndex={0}
key={key}
parent={parent}
rowIndex={index}>
{({measure}) => (
<div key={key} style={style}>
<ResizeObservable onResize={measure}>
<Post/>
</ResizeObservable>
</div>
)}
</ReactVirtualized.CellMeasurer>
)
}
如您所见,每次调整大小时都会调用测量函数。这还包括何时加载图像或 iframe,因此无需手动调用它们
我在呈现 Feed 时遇到了与 Facebook 几乎相同的问题。一渲染很多post,性能问题就出现了。经过一些研究后,我发现了 react-virtualized,这很棒,但我很难让它适用于我的应用程序。
这些是我面临的问题:
- 由于每个 post 都可以嵌入 iframe 或图像,所以一旦这些项目加载完毕,我就会从
CellMeasurer
触发measure
回调。因此,有些项目似乎错位。每次调用measure
回调时,我都尝试执行parent.measureAllRows()
和parent.recomputeRowHeights()
以查看它是否会修复它,但它没有。 - 每个 post 都有一个可展开的部分,因此我需要重新计算它的高度。除了将道具发送到组件之外,还有其他选择吗?
这是设置:
class VirtualPostList extends React.PureComponent {
constructor(props, context) {
super(props, context);
this._cache = new ReactVirtualized.CellMeasurerCache({
fixedWidth: true,
defaultHeight: 400
});
this.rowRenderer = this.rowRenderer.bind(this);
}
rowRenderer({index, isScrolling, key, parent, style}) {
return (
<ReactVirtualized.CellMeasurer
cache={this._cache}
columnIndex={0}
key={key}
parent={parent}
rowIndex={index}>
{({measure}) => (
<div key={key} style={style}>
<Post onLoad={measure}/>
</div>
)}
</ReactVirtualized.CellMeasurer>
)
}
componentDidUpdate(){
this.listComponent.recomputeRowHeights();
}
render() {
const cache = this._cache;
const rowCount = this.props.posts.length;
const _this = this;
return (
<ReactVirtualized.WindowScroller>
{({height, isScrolling, onChildScroll, scrollTop}) =>
<ReactVirtualized.AutoSizer disableHeight>
{({width}) =>
<ReactVirtualized.List
autoHeight
isScrolling={isScrolling}
height={height}
width={width}
rowCount={rowCount}
deferredMeasurementCache={cache}
rowHeight={cache.rowHeight}
rowRenderer={this.rowRenderer}
scrollTop={scrollTop}
onScroll={onChildScroll}
ref={(listComponent) => _this.listComponent = listComponent}
/>
}
</ReactVirtualized.AutoSizer>}
</ReactVirtualized.WindowScroller>
)
}
}
重叠示例:
正如@brianvaughn 所建议的,我并没有在每个应该调用的地方调用 measure
方法。这些变得有点样板并且难以维护,因为元素不仅有图像,而且它们可以自行扩展或收缩。
因为我想避免手动调用 measure
,所以我将 ResizeObserver 附加到组件,就像 ReactMeasure
一样。之后,我将 rowRenderer
函数更改为:
rowRenderer({index, isScrolling, key, parent, style}) {
return (
<ReactVirtualized.CellMeasurer
cache={this._cache}
columnIndex={0}
key={key}
parent={parent}
rowIndex={index}>
{({measure}) => (
<div key={key} style={style}>
<ResizeObservable onResize={measure}>
<Post/>
</ResizeObservable>
</div>
)}
</ReactVirtualized.CellMeasurer>
)
}
如您所见,每次调整大小时都会调用测量函数。这还包括何时加载图像或 iframe,因此无需手动调用它们