如何设置可以在 react-select 中选择的最大项目数?

Posted

技术标签:

【中文标题】如何设置可以在 react-select 中选择的最大项目数?【英文标题】:How to set max number of items that can be selected in react-select? 【发布时间】:2019-08-02 18:52:00 【问题描述】:

我正在使用 react-select 中的 CreatableSelect 组件。现在用户可以选择任意数量的项目,但我希望用户选择不超过 5 个项目。如何限制可以选择的最大选项数?

<CreatableSelect
  classes=classes
  styles=selectStyles
  textFieldProps=
    label: "Tags"
  
  options=suggestions
  components=components
  value=this.state.multi
  onChange=this.handleChange("multi")
  placeholder=""
  isMulti
/>

【问题讨论】:

通过将此逻辑添加到onChange 处理程序。只需选择前五个即可。 什么意思?你能更精确或显示代码吗? 假设您的处理程序每​​次更改时都会收到新的选择,我猜处理程序的参数将是选择作为数组。然后在调用setState(() =&gt; ( multi: selectionArray.slice(4) )) 时对这个数组进行切片。 或者,您可以对数组的末尾进行切片以获得最新的选择,这取决于结果如何传递给处理程序。 【参考方案1】:

我发现了一种更简单、更干净的方式,无需额外的操作。 这种方式基于禁用“react-select”的输入组件。 仔细看看参数inputProps

它可能看起来像:

import Select from 'react-select';
import useField from 'client/components/hooks/useField';

const MultiSelect = (
  async,
  creatable,
  maxItems,
  ...restProps,
) => 
  const selectProps = 
    ...restProps,
    // "inputProps: disabled: boolean" - our goal
    ...(typeof maxItems === 'number' && maxItems === restProps.value?.length ? inputProps: disabled: true : ) 
  ;
  const creatableTag = async ? Select.CreatableAsync : Select.Creatable;
  const SelectTag = creatable ? creatableTag : selectTag;

  return (
    <div>
      <SelectTag ...selectProps />
    </div>
  );
;

const SomeComponentWithMultiSelect = () => 
  const field = useField('data.name'); // field contains: value: string[], ...
  const items = [
    
      label: 'firstValue',
      value: 1,
    ,
    
      label: 'secondValue',
      value: 2,
    ,
  ];

  return (
    <MultiSelect
      items=items
      ...field
      creatable
      maxItems=1 // 1 as our limit
    />
  )
;

export default SomeComponentWithMultiSelect;

因此您无需管理多余的组件。

【讨论】:

【参考方案2】:

一个非常简单的方法是:

<Select
        value=tags
        onChange=(v) => v.length < 4 ? setTags(v): null
        isMulti
        name='tags'
        options=options
        className='basic-multi-select'
        classNamePrefix='select'
      />

只需添加一个简单的三元检查来检查您想要多少项目

【讨论】:

【参考方案3】:

我正在分享我认为它可以提供帮助的完整工作组件>>

import React,  useState  from 'react';
import Select from 'react-select';
import makeAnimated from 'react-select/animated';
const animatedComponents = makeAnimated();

const ReactSelect = ( data ) => 
    const maxOptions = 5;
    const [selectedOption, setSelectedOption] = useState([]);
    const handleTypeSelect = e => 
        setSelectedOption(e);
    ;

    return (
        <Select
            onChange=handleTypeSelect
            getOptionLabel=x => x.name
            getOptionValue=x => x.slug
            components=animatedComponents
            isMulti
            options=selectedOption.length === maxOptions ? [] : data
            noOptionsMessage=() => 
                return selectedOption.length === maxOptions
                    ? 'You have reached the max options value'
                    : 'No options available';
            
            label='tags'
        />
    );
;

export default ReactSelect;

【讨论】:

【参考方案4】:

有关如何解决此问题的主要文档可在此处找到:

https://github.com/JedWatson/react-select/issues/1341

const MultiCreatable = ( options, handleChange, handleCreate, value, maxOptions ) => 
  return (
    <CreatableSelect
      isMulti
      placeholder=placeholder
      onChange=handleChange
      options=value.length === maxOptions ? [] : options
      noOptionsMessage=() => 
        return value.length === maxOptions ? 'You have reached the max options value' : 'No options available' ;
      
      onCreateOption=handleCreate
      value=value
    />
  )

【讨论】:

请添加一些关于您的代码的解释,它的作用以及它是如何做的并回答问题【参考方案5】:

就我而言,我使用了来自 react-select 的普通 Select 组件。

<Select 
     options=industries
     value=industry
     getOptionLabel= x => x.id
     getOptionValue= x => x.industry
     onChange=(e) => this.handleSelectChange(e, "industry")
     isMulti
/>

和handleSelectChange-

handleSelectChange = (e, name) => 
    console.log(e)
    if(e.length < 6)
        return this.setState(
            [name]: e
        )
    

和状态 -

this.state =  industry: [] 

【讨论】:

【参考方案6】:
<CreatableSelect
        classes=classes
        styles=selectStyles
        options=this.state.multi.length > 4 ? this.state.multi : suggestions
        components=Components
        value=this.state.multi
        placeholder="Tags"
        onChange=(values) => this.setState( multi: values )
        isValidNewOption=isValidNewOption //Look at Marked Answer
        isMulti
/>

【讨论】:

添加对options的检查并仅在低于限制时才设置数据是完整的解决方案。【参考方案7】:

我建议您使用自定义组件MenuisValidNewOption 的组合,如以下代码:

// For this example the limite will be 5
    const Menu = props => 
      const optionSelectedLength = props.getValue().length || 0;
      return (
        <components.Menu ...props>
          optionSelectedLength < 5 ? (
            props.children
          ) : (
            <div>Max limit achieved</div>
          )
        </components.Menu>
      );
    ;

    function App() 
      const isValidNewOption = (inputValue, selectValue) =>
        inputValue.length > 0 && selectValue.length < 5;
      return (
        <div className="App">
          <Creatable
            components= Menu 
            isMulti
            isValidNewOption=isValidNewOption
            options=options
          />
        </div>
      );
    

这里是live example。

这个想法是防止用户访问限制 X 之后的选项(示例中为 5),并防止通过 isValidNewOption 属性创建时的 enter 键盘事件。

【讨论】:

非常感谢。它帮助我解决了我的问题。 如果您手动输入另一个选项并按 Enter,或者您输入并按 Tab 键,这将不起作用 - 这将允许输入超过定义的限制。 无论有没有isValidNewOption tbh,我都看不出有什么不同 @nickornotto 如果您不使用isValidNewOption,您仍然会看到Max limit achieved,但是如果您开始输入与任何选项都不匹配的文本,您将能够创建一个新选项并超过限制 好的,谢谢,我只在Select 上尝试过,Creatable 上有意义

以上是关于如何设置可以在 react-select 中选择的最大项目数?的主要内容,如果未能解决你的问题,请参考以下文章

使用 cypress 选择 react-select 下拉列表选项

react-select 默认值设置但未突出显示

如何有多个反应选择选项

如何在选择的选项上方插入标题?

如何以编程方式清除/重置 React-Select?

Formik官方应用案例解析使用react-select