How to get "key" prop from React element (on change)?

Solution 1:

You will need to pass value in key as a different prop.

From docs:

Keys serve as a hint to React but they don’t get passed to your components. If you need the same value in your component, pass it explicitly as a prop with a different name:

Read: https://reactjs.org/docs/lists-and-keys.html

Solution 2:

Passing key as a prop works obviously, but much quicker way could be to include the key as a custom attribute in your html.

class App extends React.Component {
  constructor(props) {
    super(props);
    this.onSelect = this.onSelect.bind(this);
  }
  onSelect(event) {
    const selectedIndex = event.target.options.selectedIndex;
        console.log(event.target.options[selectedIndex].getAttribute('data-key'));
  }

  render() {
    return ( 
      <div>
      <select onChange = {this.onSelect}>
       <option key="1" data-key="1">One</option> 
       <option key="2" data-key="2">Two</option>             </select> 
     </div>
    );
  }
}

ReactDOM.render( < App / > , document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Solution 3:

Imagine a component like this:

<Component data={[{id:'a23fjeZ', name="foo"}, ...]}` 

Which renders a list of inputs, and gets in a data prop which is a collection (Array of Objects):

function Component ( props ){
    // cached handler per unique key. A self-invoked function with a "cache" object
    const onChange = (cache => param => {
        if( !cache[param] )
            cache[param] = e => 
                console.log(param, e.target.name, e.target.value)

        return cache[param];
    }
    )({});

    return props.data.map(item =>
        <input key={item.id} name={item.name} onChange={onChange(item.id)} />
    }

}

As you can see, the key isn't being accessed, but is passed into a currying function which is handling the caching internally, to prevent "endless" creation of functions on re-renders.

Solution 4:

So you do need to pass the key into the <option> as a prop, but since the <select> is a native field and handles changes internally it gets a little hard to get that key value back out. Lets start one issue at a time, passing the prop into the option could be as simple as wrapping the option component like so and using the index prop as the new key prop.

const CustomOption = ({ value, children, index }) => (
    <option key={index} value={value}>{value}</option>
);

Also note that we're creating a custom component wrapper above to swallow the index prop from being applied to <option /> itself as react doesnt like unknown props on dom elements.

Now if we could handle the selected event inside the option we would be done, but we can't do that. so we need to make a custom select as well:

class CustomSelect extends React.Component {

    static propTypes = {
        value: PropTypes.object,
        onChange: PropTypes.func,
    }

    handleChanged = (e) => {
        const newValue = e.target.value;
        let newKey;

        // iterate through our children searching for the <CustomOption /> that was just selected
        React.children.forEach(this.children, (c) => {
            if (c.props && c.props.index && c.props.value === newValue) {
                newKey = c.props.key;
            }
        });

        this.props.onChange(e, newKey);
    }

    render() {
        return (
            <select value={this.props.value} onChange={this.handleChanged}>
                {this.props.children}
            </select>
        );
    }
}

it has two props value, and onChange. Notice that we intercept the change event in order to find the index (the key) and we pass it along to the parent as the second parameter. This is not very nice but I can't think of another easy way to do this while still using the native <select> element.

Note you need to replace your usages of <select> and <optoin> to use these new classes, and assign the index prop along with the key prop on the option.