我一直在尝试对 React-Select 组件实现虚拟化,但没有成功。准确地说,我尝试使用的每个虚拟化包都存在某种我无法解决的重大故障:
可能是因为我缺乏经验而把一些事情搞砸了,但即使直接复制粘贴其他人的解决方案,我最终也会遇到麻烦。我相信这与上面的大多数虚拟化包没有完全适应选择的 v5 或 TypeScript 或 React 18 等有关。
任何帮助将不胜感激!提前谢谢你:)
与此相关的答案: 反应虚拟化:由于某种原因,仍然有点不稳定,也破坏了图形错误(就像第二行中出现的任何文本显示在下一个选项中一样)
为了防止第二行出现在下一个选项中,您需要一个 CellMeasurerCache
当列表大小(宽度)发生变化时,它会自动重新计算可见框架中每行的高度。
当然这不是一个完美的解决方案,但它满足您的要求
import React, { useMemo } from 'react'
import AsyncSelect from 'react-select/async'
import { List, AutoSizer, CellMeasurer, CellMeasurerCache } from 'react-virtualized'
import type { MenuListProps, GroupBase } from 'react-select'
import type { ListRowProps } from 'react-virtualized'
type ListOption = {
label: string
value: string
}
const VirtualizedList = ({ children }: MenuListProps<ListOption, false, GroupBase<ListOption>>) => {
const rows = children
const cellCache = useMemo(() => {
return new CellMeasurerCache({
fixedWidth: true,
defaultHeight: 30
})
}, [])
if (!Array.isArray(rows)) {
// For children like: "Loading" or "No Options" provided by 'react-select'
return <>{children}</>
}
const rowRenderer = ({ key, parent, index, style }: ListRowProps) => (
<CellMeasurer cache={cellCache} key={key} columnIndex={0} rowIndex={index} parent={parent}>
<div key={key} style={style}>
{rows[index]}
</div>
</CellMeasurer>
)
return (
<div style={{ height: '300px' }}>
<AutoSizer>
{({ width, height }) => (
<List
width={width}
height={height}
deferredMeasurementCache={cellCache}
rowHeight={cellCache.rowHeight}
rowCount={rows.length}
rowRenderer={rowRenderer}
/>
)}
</AutoSizer>
</div>
)
}
export const Example = () => {
return (
<div>
<AsyncSelect
cacheOptions
components={{ MenuList: VirtualizedList }}
defaultOptions={'YOUR DEFAULT DATA'}
loadOptions={'YOUR DATA FROM SOMEWHERE'}
styles={{
menu: ({ position, fontWeight, ...provided }) => ({
...provided,
position: 'static'
})
}}
/>
</div>
)
}