1
votes

I am getting this:

Warning: Each child in an array or iterator should have a unique "key" prop.

Here is my code of Dropdown Component:

render() {
    let dropDownClasses = [classes["im-dropdown"], classes[this.state.size], classes[this.state.dropStyle], classes[this.status]];
    let itemcount = -1;
    let options;
    if(this.state.options !== undefined){
        options = this.state.options.map(option => {
            itemcount++;
            return(<div><li key ={'opt_'+this.state.name+'_'+itemcount}  role="option" aria-selected="false" value={option.value} tabIndex={itemcount} onClick={this.handleSelect.bind(this, this.state.name, option.value, option.text)}>  {option.text} </li></div>)
        });
    }

    return (
        <div className={dropDownClasses.join(' ')}>
            <button aria-haspopup="listbox" aria-expanded="false" onClick={this.handleOpen}>
                <span>{this.state.label}</span><span className={classes["caret"]}><i className="fa fa-angle-down"></i></span>
            </button>
            <ul className={classes["options"]} role="listbox" aria-labelledby={"im-drop_" +this.state.size+"_"+this.state.dropStyle} >
                <span key ={'opt_'+this.state.name+'_'+itemcount}>{options} </span>
            </ul>
        </div>
    );
}

and I am calling it through another component as SideDrawer.js like this:

    <div>
        <span className ={classes["filter"]}><strong>FILTER BY</strong></span>
    </div> 
    <Dropdown key={'opt_'+ clientDropdown.label} label={clientDropdown.label} name={clientDropdown.name} options={clientDropdown.options} action={props.formHandler}/>
    <Dropdown  label={typeDropdown.label} name={typeDropdown.name} options={typeDropdown.options} action={props.formHandler}/>
    <Dropdown  label={categoryDropdown.label} name={categoryDropdown.name} options={categoryDropdown.options} action={props.formHandler}/>
</div>

The warning seems to be coming since I am invoking Dropdown components multiple times in a single div (more like an array of items) thereby causing Key warning. I tried to use "key" as a prop but it doesn't _

4
please finish the last phrase (I've added "_" where something is missing). I've also improved formatting of your post for you, please do so in your next questions and/or answers. Best regards - YakovL

4 Answers

2
votes
  1. Don't bind the function directly in render instead bind it in constructor always
  2. Don't enclose li into div
  3. Try to keep render part as much as clean
  4. You are setting key to li but not to div and that's why you get the warning
  5. Also when you do loop, you need to set the key to the parent jsx element and key should be from data which should be unique. If you don't get unique id per object from data then use index as key something like below. Keep in mind that index is always second option.

I have simplified your code as much as possible

constructor(props){
  super(props);
  this.handleSelect = this.handleSelect.bind(this);
}
render() {
    const { options, name, label, dropStyle, size } = this.state;
    const dropDownClasses = [classes["im-dropdown"], classes[size], classes[dropStyle], classes[this.status]];
    return (
        <div className={dropDownClasses.join(' ')}>
            <button aria-haspopup="listbox" aria-expanded="false" onClick={this.handleOpen}>
                <span>{label}</span><span className={classes["caret"]}><i className="fa fa-angle-down"></i></span>
            </button>
            <ul className={classes["options"]} role="listbox" aria-labelledby={"im-drop_" +size+"_"+dropStyle} >
                  {Array.isArray(options) && options.length && options.map((option, index) => (
                      <li key ={`Key_${index}`} role="option" aria-selected="false" value={option.value} tabIndex={index} onClick={() => this.handleSelect(name, option.value, option.text)}>  {option.text} </li>
                  ))}
            </ul>
        </div>
    );
}
1
votes

Move the key to the parent div, also you might want to remove the redundant space after the key. You also can you the index param instead of your item count.

    options = this.state.options.map((option, index) => {
        return(<div key={'opt_'+this.state.name+'_'+index}><li role="option" aria-selected="false" value={option.value} tabIndex={itemcount} onClick={this.handleSelect.bind(this, this.state.name, option.value, option.text)}>  {option.text} </li></div>)
    });
0
votes

while iterating and returning any html elements using map function unique key is required for each and every element otherwise you will get warnings, that because of node elements mounts on key, but its not mandatory to give keys but for best performance and zero bug code its required .

in your code you should give key to parent element that is , hence your giving key to child elements map function not considering as map keys

your code:

if(this.state.options !== undefined){
        options = this.state.options.map(option => {
            itemcount++;
            return(<div><li key ={'opt_'+this.state.name+'_'+itemcount}  role="option" aria-selected="false" value={option.value} tabIndex={itemcount} onClick={this.handleSelect.bind(this, this.state.name, option.value, option.text)}>  {option.text} </li></div>)
        });
    }

fix code: key should be in parent element

if(this.state.options !== undefined){
        options = this.state.options.map(option => {
            itemcount++;
            return(<div key ={'opt_'+this.state.name+'_'+itemcount} ><li role="option" aria-selected="false" value={option.value} tabIndex={itemcount} onClick={this.handleSelect.bind(this, this.state.name, option.value, option.text)}>  {option.text} </li></div>)
        });
    }
0
votes
if(this.state.options !== undefined){
    options = this.state.options.map((option,i) => {
        itemcount++;
        return(<div key={i}><li   role="option" aria-selected="false" value={option.value} tabIndex={itemcount} onClick={this.handleSelect.bind(this, this.state.name, option.value, option.text)}>  {option.text} </li></div>)
    });
}

when you create a component in array, should give a key in parent component, now i set index as a key ..hope it will help to you