我正在尝试使用react-virtualized渲染具有1000多个数据行的表。这些行非常重,包含多个复杂的React组件。输入,组合框,日期选择器和弹出菜单全部排在一行中。我需要整个窗口来滚动这些行。
我还需要对行进行分组并将其嵌套到显示/隐藏样式的手风琴组件中。
[+] Row Header 1
row 1
row 2
...
row 1001
[+] Row Header 2
row 1
row 2
...
row 1001
我不确定如何处理这种用例,或者不确定React-Virtualized是否可以处理此类事情。
我尝试过的事情:
结合使用WindowScroller / AutoSizer / List组件,并将这组由反应虚拟化的组件放入每个手风琴中。这有效,但不能解决我的问题。之所以会出现问题,是因为浏览器仍然无法处理(首次加载大约需要25秒,并且无法滚动)
我还需要使用WindowScroller / AutoSizer / List组件来处理行标题的第一级吗?
任何想法或例子将不胜感激。
答案 0 :(得分:0)
您至少可以释放 UI 线程以供网络工作者滚动(当然这是一个重要的 UX 原则)。
这是一个 medium-length discussion article with an example、一个 quick implementation doc(和 the great matching article)和一个 my all-time favorite talk on the subject。
这会推迟主“UI”线程的工作,但如果工作可以通过 useMemo() 钩子记忆,您也可以首先防止这种推迟。
答案 1 :(得分:0)
反应虚拟化的关键部分是 recomputeRowHeights
您可以通过此实现预期的结果。
import React, { useState, useRef, useEffect } from "react";
import {
AutoSizer,
Column,
Table,
defaultTableRowRenderer
} from "react-virtualized";
const Component = ({ list }) => {
const [selectedIndex, setSelectedIndex] = useState(-1);
const tableRef = useRef();
const Details = ({ children, index }) => (
<div style={{ cursor: "pointer" }} onClick={() => setSelectedIndex(index)}>
{children}
</div>
);
const _getDatum = index => list[index % list.length];
const _getRowHeight = ({ index }) => (index === selectedIndex ? 96 : 48);
const rowGetter = ({ index }) => _getDatum(index);
const cellRenderer = ({ rowIndex }) => {
if (rowIndex !== selectedIndex) {
return <Details index={rowIndex}>+</Details>;
} else {
return <Details index={-1}>-</Details>;
}
};
useEffect(
() => {
tableRef.current.recomputeRowHeights();
},
[selectedIndex]
);
const rowRenderer = props => {
const { index, style, className, key, rowData } = props;
if (index === selectedIndex) {
return (
<div
style={{ ...style, display: "flex", flexDirection: "column" }}
className={className}
key={key}
>
{defaultTableRowRenderer({
...props,
style: { width: style.width, height: 48 }
})}
<div
style={{
marginRight: "auto",
marginLeft: 80,
height: 48,
display: "flex",
alignItems: "center"
}}
>
{rowData.details}
</div>
</div>
);
}
return defaultTableRowRenderer(props);
};
return (
<div style={{ height: "90vh" }}>
<AutoSizer>
{({ width, height }) => (
<Table
ref="Table"
headerHeight={56}
height={height}
overscanRowCount={10}
rowHeight={_getRowHeight}
rowGetter={rowGetter}
rowCount={1000}
width={width}
ref={tableRef}
rowRenderer={rowRenderer}
>
<Column
label="Index"
cellDataGetter={({ rowData }) => rowData.length}
cellRenderer={cellRenderer}
dataKey="index"
disableSort
width={60}
/>
<Column dataKey="name" disableSort label="Full Name" width={120} />
</Table>
)}
</AutoSizer>
</div>
);
};
export default Component;