Как отобразить несколько схем форм неизвестной высоты в строках React Virtualized
В настоящее время я работаю над проектом, где у нас есть длинная страница информации, которая разбита на разделы для целей категоризации. У каждого раздела есть заголовок, в котором указано, что это за раздел, а тело этого раздела генерируется с помощью response-jsonschema-form на лету. Затем каждый раздел может быть заполнен или изменен пользователем для изменения данных, которые он видит, так что разделы могут расширяться или сжиматься в зависимости от выбранных или сохраненных параметров (установите флажок, может появиться другое поле с просьбой уточнить ваш выбор), Поскольку разделов так много, мы подумали, что было бы неплохо их виртуализировать, но у нас возникают проблемы с рендерингом с правильной высотой и прокруткой.
Мы используем React 16.8.6, @material-ui/core 3.9.2, response-jsonschema-form 1.4.0 и response-virtualized 9.21.0. у меня есть WindowScroller
установить с AutoSizer
внутри (чтобы дать мне отзывчивую ширину на всех внутренних элементах), а затем я использую List
компонент для визуализации моих разделов (отформатированный с помощью компонентов пользовательского интерфейса материалов и содержащий формы JsonSchema).
Я могу создать разделы, но каждый из них изначально имеет высоту всего 71px, что включает в себя высоту заголовка раздела и отступ от тела (но без содержимого). Я настроил CellMeasurer
а также CellMeasurerCache
Таким образом, у нас есть высоты, сохраненные в указанном кэше, но они всегда отображаются как 71px ... они не сбрасываются, когда тела разделов правильно отображаются через несколько секунд после появления заголовков. Я решил поставить clearAll()
функция в 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>
)
}
Прежде всего мне любопытно, правильно ли все это настроено... и является ли List правильным компонентом, который будет использоваться для многих строк одной ячейки, карты с заголовком и тела, содержащего информацию о форме? Кроме того, как и при каждом прокрутке onRowRenderer
Кажется, что функция вызывается, чтобы вызвать CellMeasurer
(и я предполагаю, что это должно определить текущее позиционирование и то, что оно должно отобразить следующим), мне было интересно, есть ли способ упростить этот процесс или он не срабатывает так часто, чтобы удерживать вызовы как минимум. Или, может быть, существует способ виртуализации только содержимого раздела, а не всей строки? Просто пытаюсь выяснить, есть ли способ использовать реагирующую виртуализацию для достижения моих целей, или мне нужно "раскрутить свое" решение здесь. Спасибо!