如何在语义UI反应中创建完全受控的下拉列表

时间:2019-03-24 16:58:45

标签: reactjs semantic-ui-react

我想创建一个完全受控的下拉菜单,以便使用https://tools.ietf.org/html/rfc6570#page-18在其中显示很长的项目列表。

我已经检查过文档,并且没有任何指定Dropdown.Item的受控下拉菜单的例子。

这是我的组件的样子:

<Dropdown
  placeholder="Filter Posts"
  clearable={true}
  search={true}
  onChange={this.handleChange}
  text={tagOptions[1].value}
  value={tagOptions[1].value}
  onSearchChange={this.handleChange}
>
  <Dropdown.Menu>
    {tagOptions.map(option => (
      <Dropdown.Item key={option.value} {...option} onClick={this.handleItemClick} />
    ))}
  </Dropdown.Menu>
</Dropdown>;

我遇到了2个问题:

  1. 初始值未出现,我深入代码,发现如果我不传递options属性,它将找不到给定值,因此将不显示该值。我可以使用text属性,但这似乎很简单。
  2. 我需要自己实现handleItemClick,我发现react-window中存在逻辑。

有什么建议吗?我在这里错过了什么吗?

3 个答案:

答案 0 :(得分:2)

dropdown模块根本不支持对其内部组件的控制,也就是说,这是我最接近使用react-window支持的受控dropdown。我将其发布在这里,供以后希望通过虚拟化轻松选择下拉菜单的任何人。

VirtualizedDropdown.js

import React, { forwardRef, useCallback, useRef, useState } from "react"
import { Dropdown, Ref } from "semantic-ui-react"
import { FixedSizeList } from "react-window"
import "./VirtualisedDropdown.scss"

const SUI_DROPDOWN_MENU_HEIGHT = 300
const SUI_DROPDOWN_MENU_ITEM_HEIGHT = 37

const VirtualisedDropdown = ({
  options, value,
  ...restProps
}) => {
  const dropdownRef = useRef()
  const listRef = useRef()

  const [open, setOpen] = useState(false)

  const OuterDiv = useCallback(({ style, ...props }, ref) => {
    const { position, overflow, ...restStyle } = style
    return (
      <Ref innerRef={ref}>
        <Dropdown.Menu open={open} {...props} style={restStyle}>
          {props.children}
        </Dropdown.Menu>
      </Ref>
    )
  }, [open])

  const InnerDiv = useCallback(props => {
    return (
      <Dropdown.Menu className="inner" open={open} style={{ ...props.style, maxHeight: props.style.height }}>
        {props.children}
      </Dropdown.Menu>
    )
  }, [open])

  return (
    <Dropdown
      className="virtualised selection"
      onClose={() => setOpen(false)}
      onOpen={() => {
        setOpen(true)
        listRef.current.scrollToItem(options.findIndex(i => i.value === value))
      }}
      // This causes "Warning: Failed prop type: Prop `children` in `Dropdown` conflicts with props: `options`. They cannot be defined together, choose one or the other."
      // but is necessary for some logic to work e.g. the selected item text.
      options={options}
      ref={dropdownRef}
      selectOnNavigation={false}
      value={value}
      {...restProps}
    >
      <FixedSizeList
        height={options.length * SUI_DROPDOWN_MENU_ITEM_HEIGHT < SUI_DROPDOWN_MENU_HEIGHT ? options.length * SUI_DROPDOWN_MENU_ITEM_HEIGHT + 1 : SUI_DROPDOWN_MENU_HEIGHT}
        innerElementType={InnerDiv}
        itemCount={options.length}
        itemData={{
          options,
          handleClick: (_e, x) => dropdownRef.current.handleItemClick(_e, x),
          selectedIndex: options.findIndex(i => i.value === value),
        }}
        itemSize={SUI_DROPDOWN_MENU_ITEM_HEIGHT}
        outerElementType={forwardRef(OuterDiv)}
        ref={listRef}
      >
        {Row}
      </FixedSizeList>
    </Dropdown>
  )
}

const Row = ({ index, style, data }) => {
  const { options, handleClick, selectedIndex } = data
  const item = options[index]

  return (
    <Dropdown.Item
      active={index === selectedIndex}
      className="ellipsis"
      key={item.value}
      onClick={handleClick}
      selected={index === selectedIndex}
      style={style}
      title={item.text}
      {...item}
    />
  )
}

export default VirtualisedDropdown

VirtualizedDropdown.scss

.ui.dropdown.virtualised .menu {
  &.inner {
    margin: 0 -1px !important;
    left: 0;
    overflow: initial;
    border-radius: 0 !important;
    border: 0;
  }

  > .item {
    text-overflow: ellipsis;
    white-space: nowrap;
    overflow: hidden;
  }
}

答案 1 :(得分:1)

我可以使用下拉菜单中的ref并传递原始的handleItemClick方法来破解它。

目前唯一的缺点是键盘导航无效:\

似乎并非旨在对其进行完全控制。

https://codesandbox.io/s/ql3q086l5q

答案 2 :(得分:0)

  1. 要解决第一个问题,请删除clearable={true}text={tagOptions[1].value}

  2. handleItemClick函数应该做什么?