如何在React-Select中设置可选择的最大项目数?

20

我正在使用来自 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”处理程序中。只保留前五个选择。 - remix23
你的意思是什么?你能更明确一些或者展示代码吗? - Bositkhon Sultonov
假设您的处理程序每次更改时都会接收新的选择,我猜处理程序的参数将是作为数组的选择。然后在调用 setState(() => ({ multi: selectionArray.slice(4) })) 时只需对该数组进行切片即可。 - remix23
或者你可以切片数组的末尾以获得最新的选择,这取决于结果如何传递给处理程序。 - remix23
7个回答

12

我建议您使用自定义组件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>
      );
    }

这里有一个实时示例

该想法是防止用户在限制X(例如示例中的5)之后访问选项,并且还通过isValidNewOption属性阻止在创建时使用enter键盘事件。


1
非常感谢。它帮助我解决了我的问题。 - Bositkhon Sultonov
如果您手动输入其他选项并按Enter键,则此方法无效,或者如果您输入并按Tab键-它将允许超过定义限制的更多条目。 - chapmanio
说实话,我看不出有和没有 isValidNewOption 有什么不同。 - nickornotto
@nickornotto 如果你不使用isValidNewOption,你仍然会看到“已达到最大限制”,但是如果你开始输入一个不匹配任何选项的文本,你将能够创建一个新的选项并超过限制。 - Laura
1
好的,谢谢。我之前只尝试了 Select,使用 Creatable 更有意义。 - nickornotto

7

一个非常简单的方法是:

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

只需添加一个简单的三元检查,以确定您想要的项目数量。

2

我分享了一个完整的可工作组件,我认为它可以帮助>>

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;

2

关于如何解决这个问题的主要文档可以在此处找到:

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}
    />
  )
}

请在您的代码中添加一些解释,说明它的作用以及如何回答问题。 - Our Man in Bananas

2
<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
/>

在“选项”上添加检查,并仅在低于限制时设置数据是完整的解决方案。 - chapmanio

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;

所以您不需要管理过多的组件。

0

对于我的情况,我使用了来自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: [] }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接