简体   繁体   English

有多个<select>元素在 React 中共享相同的选项?

[英]Have multiple <select> elements share the same options in React?

So I have a React component like:所以我有一个 React 组件,如:

export default function ExampleComponent() {
    return (
        <div>
            <select required name="select1">
                <option label=" "></option>
                <option value="option1">Option 1</option>
                <option value="option2">Option 2</option>
                <option value="option3">Option 3</option>
            </select>

            <select name="select2">
                <option label=" "></option>
                <option value="option1">Option 1</option>
                <option value="option2">Option 2</option>
                <option value="option3">Option 3</option>
            </select>
        </div>
    );
}

Continuing on for multiple more selects...继续进行多个选择...

I want it so that when I select one option in any of the select tags, it gets removed as an option in all of the others.我想要它,以便当我在任何选择标签中选择一个选项时,它会作为所有其他选项中的一个选项被删除。 If I change the selected option, it then becomes available again in all of the others.如果我更改选定的选项,它就会在所有其他选项中再次可用。 Does anyone know how I would be able to do this in React?有谁知道我如何在 React 中做到这一点?

You have to use state to manage the value and share it between two select s.您必须使用state来管理值并在两个select之间共享它。

 import React, {useState} from 'react' export default function ExampleComponent() { const [value, setValue] = useState('option0') handleChange = (e) => { setValue(e.target.value) } return ( <div> <select value={value} onChange={handleChange}> <option value="option0"></option> <option value="option1">Option 1</option> <option value="option2">Option 2</option> <option value="option3">Option 3</option> </select> <select value={value} onChange={handleChange}> <option value="option0"></option> <option value="option1">Option 1</option> <option value="option2">Option 2</option> <option value="option3">Option 3</option> </select> </div> ); }

Why don't you use state?你为什么不使用状态? You can use same datasource for options and also same event handlers for all selects.您可以为选项使用相同的数据源,也可以为所有选择使用相同的事件处理程序。

export default function ExampleComponent() {
  state = {
    options: [
      {
        name: 'Option 1',
        value: 'option1'
      },
      {
        name: 'Option 2',
        value: 'option2'
      },
      {
        name: 'Option 3',
        value: 'option3'
      }
    ]
  };

  onChangeSelect = event => {
    // do something
    this.setState({
      options: this.state.options.filter(
        option => option.value !== event.target.value
      )
    });
  };

  return (
    <div>
      <select required name="select1" onChange={onChangeSelect}>
        <option label=" "></option>
        {this.state.options.map(option => (
          <option value={option.value}>{option.name}</option>
        ))}
      </select>

      <select name="select2" onChange={onChangeSelect}>
        <option label=" "></option>
        {this.state.options.map(option => (
          <option value={option.value}>{option.name}</option>
        ))}
      </select>
    </div>
  );
}

There may be a more elegant way to do this, but my thought was to keep track of which select have chosen which option with a object called chosenObjects then filtering results based on that information.可能有一种更优雅的方法来做到这一点,但我的想法是跟踪哪个select选择了哪个选项,并使用一个名为chosenObjects的对象,然后根据该信息过滤结果。

import React, {useState} from "react";

export default function ExampleComponent() {
    const selectNames = ["select1", "select2"];
    const [options] = useState([
        {
            label: 'Option 1',
            value: 'option1'
        },
        {
            label: 'Option 2',
            value: 'option2'
        },
        {
            label: 'Option 3',
            value: 'option3'
        }
    ]);


    const [chosenOptions, setChosenOptions] = useState({});

    const isChosenByOther = (optionValue, selectName) => {
        for (let key in chosenOptions) {
            if (key !== selectName) {
                if (chosenOptions[key] === optionValue) {
                    return true;
                }
            }
        }
        return false;
    };

    const handleChange = (ev) => {
        setChosenOptions({...chosenOptions, [ev.target.name]: ev.target.value});
    };

    return (
        <div>
            {selectNames.map((name, index) => {
                return (
                    <select name={name} key={index} onChange={handleChange} value={chosenOptions[name] || ''}
                            required={index === 0}>
                        <option value=''/>
                        {options.filter(({value}) => !isChosenByOther(value, name))
                            .map(({label, value}, oIndex) =>
                                <option value={value} key={oIndex}>{label}</option>)
                        }
                    </select>
                )
            })}
        </div>
    );
}

You can also conditionally disable your empty string valued option after something is chosen:您还option在选择某些内容后有条件地禁用空字符串值option

<div>
    {selectNames.map((name, index) => {
        return (
            <select name={name} key={index} onChange={handleChange} value={chosenOptions[name] || ''}
                    required={index === 0}>
                <option value='' disabled={chosenOptions[name]}>Choose Option</option>
                {options.filter(({value}) => !isChosenByOther(value, name))
                    .map(({label, value}, oIndex) =>
                        <option value={value} key={oIndex}>{label}</option>)
                }
            </select>
        )
    })}
</div>

You need to track the state of multiple Select elements, and then conditionally render the options for each one.您需要跟踪多个Select元素的状态,然后有条件地为每个元素渲染选项。

I'll use some bits from the other answers and show how to make it work.我将使用其他答案中的一些内容并展示如何使其工作。 Edited to keep the options in the same order.编辑以保持选项的顺序相同。

import React, {useState} from "react";
function ExampleComponent() {
    const [myState, setMyState] = useState({});
    const options = [
        {
            name: 'Option 1',
            value: 'option1'
        },
        {
            name: 'Option 2',
            value: 'option2'
        },
        {
            name: 'Option 3',
            value: 'option3'
        }
    ]

    // list of select names
    const selectNames = [
        "select1",
        "select2"
    ]

    handleChange = (e) => {
        // update the value for the given select
        myState[e.target.name] = e.target.value
        setMyState(myState)
    }

    const inUseValues = Object.values(myState);

      console.log(inUseValues)

    // get the options for given name
    getOptions = (name) =>
        options.filter(option => !inUseValues.includes(option.value) || myState[name]==option.value)
        .map(option => (
            <option key={option.value} value={option.value}>{option.name}</option>
        ))

    // render all select controls
    const selectRender = selectNames.map(name => (
        <select key={name} required name="{name}" value={myState[name]} onChange={handleChange}>
            <option label=" "></option>
            {getOptions(name)}
        </select>
        ))

    return (
        <div>
            {selectRender}
        </div>
    )

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM