【问题标题】:How to set max number of items that can be selected in react-select?如何设置可以在 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) })) 时对这个数组进行切片。
  • 或者,您可以对数组的末尾进行切片以获得最新的选择,这取决于结果如何传递给处理程序。

标签: javascript reactjs jsx react-select


【解决方案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 上有意义
          猜你喜欢
          • 2010-10-10
          • 2021-11-22
          • 2021-01-15
          • 2022-08-10
          • 2013-01-25
          • 2019-09-29
          • 2019-07-01
          • 2019-08-21
          • 2013-08-16
          相关资源
          最近更新 更多