如何虚拟化 React-Select 的选项?

问题描述 投票:0回答:1

我一直在尝试对 React-Select 组件实现虚拟化,但没有成功。准确地说,我尝试使用的每个虚拟化包都存在某种我无法解决的重大故障:

  • react-select-virtualized:图形错误,选择根本不起作用
  • react-virtualized:出于某种原因,仍然有点不稳定,也破坏了图形错误(就像下一个选项中显示的第二行中的任何文本一样)
  • react-window:根本无法让它工作
  • react-virtual:非常不稳定(可能根本无法工作)
  • react-virtuoso:仍然非常不稳定且无法使用(虽然比正常情况稍好一些,但对于产品来说还不够好。)

可能是因为我缺乏经验而把一些事情搞砸了,但即使直接复制粘贴其他人的解决方案,我最终也会遇到麻烦。我相信这与上面的大多数虚拟化包没有完全适应选择的 v5 或 TypeScript 或 React 18 等有关。

任何帮助将不胜感激!提前谢谢你:)

reactjs typescript virtualization react-select react-virtualized
1个回答
0
投票

与此相关的答案: 反应虚拟化:由于某种原因,仍然有点不稳定,也破坏了图形错误(就像第二行中出现的任何文本显示在下一个选项中一样)


为了防止第二行出现在下一个选项中,您需要一个 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>
  )
}

© www.soinside.com 2019 - 2024. All rights reserved.