Reactのリストコンポーネントのkeyにindexを使ってはいけない

React始めて1か月たった。 調べものをしていると、サンプルコードでlistコンポーネントのkeyにindexを使っているものがたまに見かけられる。 こんなの

render() {
   const list = this.props.usernames.map((username,index) => {
     return <li key={index}>username</li>
   });
   return (
     <ul>{list}</ul>
   );
}

...不変なリストであればこれで問題ないのかもしれないが、 リストの中身を変更したときにdomを差分更新することができないらしい。

例えばリストの中に入力エリアがある場合、入力内容はリストの変更に追随しない。

import React, { Component } from 'react';

class InputArea extends Component {
  render() {
    return (
      <div className="form-group row">
        <label className="col-sm-2 col-form-label">{this.props.label}</label>
        <div class="col-sm-10">
          <input type="text" className="form-control" />
        </div>
      </div>
    )
  };
}

class Question extends Component {
  constructor(props) {
    super(props);
    this.state = {
      questions: [
        { id: 1525018854, label: 'do you like apple?' },
        { id: 1525018844, label: 'do you like banana?' },
        { id: 1525018824, label: 'do you like orange?' },
      ]
    }
  }

  add = () => {
    const question = { id: +new Date, label: this.refQuestion.value };
    this.setState({
      questions: [question].concat(this.state.questions)
    });
  };

  render() {
    const questionList = this.state.questions.map((question, index) => {
      return <InputArea key={index} label={question.label} />
    });
    return (
      <div>
        {questionList}
        <div className="form-group">
          <textarea className="form-control" placeholder='question?' ref={(elm) => { this.refQuestion = elm; }} />
          <button className="btn btn-primary" onClick={this.add}>add</button>
        </div>
      </div>
    )
  }
}

f:id:schiughi:20180430023334g:plain

Eslint使ってなければ気付かなかったと思う。

参考

medium.com