我目前正在从事一个项目,该项目中有一长页信息,出于分类目的,这些信息会分成多个部分。每个部分都有一个标头,用于说明该部分是什么,该部分的主体是通过react-jsonschema-form动态生成的。然后,用户可以填写或操纵每个部分以更改他们看到的数据,因此这些部分可以根据选择或保存的选项进行扩展或收缩(选中一个复选框,可能会出现另一个字段,要求您详细说明选择内容) 。因为有很多部分,我们认为最好对它们进行虚拟化,但是我们遇到了用适当的高度进行渲染和滚动的问题。
我们正在使用React 16.8.6,@ material-ui / core 3.9.2,react-jsonschema-form 1.4.0和react-virtualized 9.21.0。我设置了一个WindowScroller
,并在其中放置了AutoSizer
(以便在所有内部元素上提供响应宽度),然后使用一个List
组件来呈现我的部分(格式为材料UI组件,并包含JsonSchema表单。
我能够生成这些节,但是它们最初的显示高度仅为71px,其中包括节头的高度和距主体的填充(但没有内容)。我已经设置了CellMeasurer
和CellMeasurerCache
,所以我们将高度存储在所说的缓存中,但是它们始终显示为71px ...一旦节头在标题之后片刻就正确呈现,它们就不会重置出现。我决定在clearAll()
的{{1}}属性中放置一个onRowsRendered
函数,这似乎起初是可行的,但是一旦我开始滚动,事情就开始变得越来越混乱了,然后一切最终都会崩溃,并显示以下错误:
List
控制台日志向我显示Uncaught Invariant Violation: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
在滚动时不断触发,我担心这是导致崩溃的原因。
最初,我的控制台中出现了第二条错误消息和堆栈跟踪,这使我进入了CellMeasurer
组件的withWidth
属性,该组件用于在不同屏幕宽度上调整节内内容区域的大小,所以我认为Hidden
的不断触发迫使CellMeasurer
组件不断测量其宽度,但是我删除了该组件,但仍然从上方得到了Hidden
。完成删除操作就是消除了第二条错误消息,现在我无休止地看到控制台日志消息,显示Invariant Violation
不断触发,即使在我停止滚动很长时间之后,也与上面的定期错误消息混在一起
这是我的代码的基本布局:
CellMeasurer
首先,我很好奇我是否正确设置了所有这些……并且列出要用于一个单元格的许多行的正确组件,带标题的卡和包含表单信息的正文吗?另外,就像每个滚动动作一样,import ResponsiveJsonForm from '../components/ResponsiveJsonForm'
class AssessmentForm extends React.Component {
cache = new CellMeasurerCache({
defaultHeight: 400,
fixedWidth: true,
})
addFormRef = section => form => {
if (form) {
this.forms[section] = form
}
}
attemptSubmit = section => success => {
this.submissions[section] = success
const successes = Object.values(this.submissions)
if (successes.length === this.props.sections.length) {
if (successes.every(Boolean)) {
this.openSignDialog()
}
this.submissions = {}
}
}
rowRenderer = ({ key, index, parent, isScrolling, isVisible, style }) => {
const section = this.props.sections[index]
return (
<CellMeasurer
cache={this.cache}
columnIndex={0}
key={key}
parent={parent}
rowIndex={index}
>
<div style={style}>
<SectionForm
key={section}
assessmentId={this.props.assessmentId}
section={section}
FormComponent={ResponsiveJsonForm}
formRef={this.addFormRef(section)}
onSubmitAttempted={this.attemptSubmit(section)}
/>
</div>
</CellMeasurer>
)
)
}
render() {
const {
classes,
sections,
} = this.props
return sections.length > 0 && (
<div className={classes.root}>
<WindowScroller>
{({ height, isScrolling, onChildScroll, scrollTop }) => (
<AutoSizer disableHeight>
{({ width }) => (
<List
autoHeight
width={width}
deferredMeasurementCache={this.cache}
isScrolling={isScrolling}
onScroll={onChildScroll}
scrollTop={scrollTop}
ref={list => (this.list = list)}
height={height}
overscanRowCount={2}
onRowsRendered={() => {
this.cache.clearAll()
}}
rowCount={sections.length}
rowHeight={this.cache.rowHeight}
rowRenderer={this.rowRenderer}
/>
)
}
</AutoSizer>
)}
</WindowScroller>
)
}
函数似乎被调用来触发onRowRenderer
(并且我认为这是确定当前位置及其下一步要呈现的内容),我想知道是否有一种方法可以简化此过程,也可以使其不频繁启动以将通话次数保持在最低水平。或者也许有一种方法可以虚拟化一个部分的内容,而不是整个行本身?只是想弄清楚是否有一种方法可以使用反应虚拟化来实现我的目标,或者我是否必须在这里“推出自己的解决方案”。谢谢!