在 React 中使用多个选项从 < select > 检索值

设置选择框选择哪个选项的 React 方法是在 <select>本身上设置一个特殊的 value道具,对应于您希望被选中的 <option>元素上的 value属性。对于 multiple选择这个道具可以接受一个数组代替。

现在,因为这是一个特殊的属性,我想知道当用户改变东西时,在相同的选项值数组结构中选择的选项 取回的规范方法是什么(这样我就可以通过一个回调传递给父组件等) ,因为大概相同的 value属性不会在 DOM 元素上可用。

举个例子,对于一个文本字段,您可以执行以下操作(JSX) :

var TextComponent = React.createClass({
handleChange: function(e) {
var newText = e.target.value;
this.props.someCallbackFromParent(newText);
},
render: function() {
return <input type="text" value={this.props.someText} onChange={this.handleChange} />;
}
});

对于这个多重选择组件来说,取代 ???的等价物是什么?

var MultiSelectComponent = React.createClass({
handleChange: function(e) {
var newArrayOfSelectedOptionValues = ???;
this.props.someCallbackFromParent(newArrayOfSelectedOptionValues);
},
render: function() {
return (
<select multiple={true} value={this.props.arrayOfOptionValues} onChange={this.handleChange}>
<option value={1}>First option</option>
<option value={2}>Second option</option>
<option value={3}>Third option</option>
</select>
);
}
});
148559 次浏览

The same way you do anywhere else, since you're working with the real DOM node as the target of the change event:

handleChange: function(e) {
var options = e.target.options;
var value = [];
for (var i = 0, l = options.length; i < l; i++) {
if (options[i].selected) {
value.push(options[i].value);
}
}
this.props.someCallback(value);
}

The following worked for me

var selectBoxObj = React.findDOMNode(this.refs.selectBox)
var values = $(selectBoxObj).val()

In case you want to use ref you can get selected values like this:

var select = React.findDOMNode(this.refs.selectRef);
var values = [].filter.call(select.options, function (o) {
return o.selected;
}).map(function (o) {
return o.value;
});

2018 ES6 update

  let select = this.refs.selectRef;
let values = [].filter.call(select.options, o => o.selected).map(o => o.value);

In the case you would like to keep track of the selected options while the form is being completed:

handleChange(e) {
// assuming you initialized the default state to hold selected values
this.setState({
selected:[].slice.call(e.target.selectedOptions).map(o => {
return o.value;
});
});
}

selectedOptions is an array-like collection/list of elements related to the DOM. You get access to it in the event target object when selecting option values. Array.prototype.sliceand call allows us to create a copy of it for the new state. You could also access the values this way using a ref (in case you aren't capturing the event), which was another answer for the question.

Another way to do it:

handleChange({ target }) {
this.props.someCallback(
Array.prototype.slice.call(target.selectedOptions).map(o => o.value)
)
}

Easiest way...

handleChange(evt) {
this.setState({multiValue: [...evt.target.selectedOptions].map(o => o.value)});
}

Try this one:

dropdownChanged = (event) => {
let obj = JSON.parse(event.target.value);
this.setState(
{
key: obj.key,
selectedName: obj.name,
type: obj.type
});
}




<select onChange={this.dropdownChanged} >
<option value={JSON.stringify({ name: 'name', key: 'key', type: "ALL" })} >All Projetcs and Spaces</option></select>

With Array.from() and e.target.selectedOptions you can perform a controlled select-multiple:

handleChange = (e) => {
let value = Array.from(e.target.selectedOptions, option => option.value);
this.setState({values: value});
}

target.selectedOptions return a HTMLCollection

https://codepen.io/papawa/pen/XExeZY

You can actually find the selectedOptions inside the target... no need to iterate over all the options. Let's imagine you want to send the values to an onChange function passed to your component as props: you can use the following function on the onChange of your multiple select.

onSelectChange = (e) => {
const values = [...e.target.selectedOptions].map(opt => opt.value);
this.props.onChange(values);
};

After spending a lot of time with this topic, and seeing that we are now all using mostly hooks and newbies may have never even dealt with classes in reactjs. I decided to update this answer so that people can easily deal with using vanilla javascript and ES6. I am also including a link to codesandbox so that people can play with the code and modify it to their application.

Here is the code, it has excessive console logs so that people can figure out what is doing what in the code and how it is doing it.

import "./styles.css"
import {useRef} from 'react'




export default function App() {


const handleSubmit = async(e) => {
e.preventDefault()
let selected = [...recipeRef.current.options]
.filter(option => option.selected)
.map(option => option.value)
console.log(new Date(), ' recipeType: ', selected)
console.log(new Date(), 'with ref: ', [...recipeRef.current.options]);
[...recipeRef.current.options].map(option => console.log(option,'; ',option.selected))
console.log([...recipeRef.current.options].filter(option => option.selected))
console.log([...recipeRef.current.options].filter(option=>option.selected).map(option => option.value))
}
const recipeRef = useRef()


return (
<div className="App">
<h1>Hello CodeSandbox example for select Multiple by Julio Spinelli</h1>
<form onSubmit={handleSubmit}>
<div className="mb-6">
<label htmlFor="text" className="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-300">Name of the Recipe</label>
<input type="text" id="text" className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" required ></input>
</div>
<div className="mb-6">
<label htmlFor="recipeType" className="block mb-2 text-sm font-medium text-gray-900 dark:text-gray-300">Recipe Type</label>
{/* <input type="text" id="text" className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" required onChange={(e)=>{setRecipeType(e.target.value)}} value={recipeType}></input> */}
<select name="recipeType" id="recipeType" ref={recipeRef} multiple={true} size={3}> {/* Step 2 - Add the reference to `select` element */}
<option value="unselected">unselected</option>
<option value="Grill">Grill</option>
<option value="Steak">Steak</option>
<option value="Pizza">Pizza</option>
</select>
</div>
<div className="flex items-start mb-6">
<div className="flex items-center h-5">
<input id="remember" aria-describedby="remember" type="checkbox" className="w-4 h-4 bg-gray-50 rounded border border-gray-300 focus:ring-3 focus:ring-blue-300 dark:bg-gray-700 dark:border-gray-600 dark:focus:ring-blue-600 dark:ring-offset-gray-800" ></input>
</div>
<div className="ml-3 text-sm">
<label htmlFor="remember" className="font-medium text-gray-900 dark:text-gray-300">Recipe uploaded?</label>
</div>
</div>
<button type="submit" className="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">Save</button>
</form>
</div>
)
}

Using event object:

handleChange(e) {
let selectedOptions = e.target.selectedOptions


// selectedOptions looks like this:
// {
//      '0': <1st selected HTMLOptionElement>,
//      '1': <2nd selected HTMLOptionElement>,
//      '2': <3rd selected HTMLOptionElement>
// }


let newArrayOfSelectedOptionValues = Object.values(selectedOptions).map(
opt => opt.value
)


this.props.someCallbackFromParent(newArrayOfSelectedOptionValues);
}

So the full ??? looks like this:

Object.values(e.target.selectedOptions).map( opt => opt.value )