2016-03-03 7 views
4

Я знаю, что есть много ответов на эту проблему, но я не мог найти тот, который точно решил мою проблему. Я получаю следующую ошибку: Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of QuestionItem. See https://fb.me/react-warning-keys for more information.Реагировать на уникальную ключевую опору

Я устанавливаю ключ для компонента, но я не могу заставить предупреждение уйти.

Основной компонент:

renderData() { 
     return this.state.data.map((data) => { 
      return (
       <QuestionItem key={data._id} data={data} delete={this.deleteItem} edit={this.editItem} /> 
      ) 
     }) 
    } 

QuestionItem компонент:

import React, { Component, PropTypes } from 'react'; 
import Card from 'material-ui/lib/card/card'; 
import CardActions from 'material-ui/lib/card/card-actions'; 
import CardHeader from 'material-ui/lib/card/card-header'; 
import CardMedia from 'material-ui/lib/card/card-media'; 
import CardTitle from 'material-ui/lib/card/card-title'; 
import FlatButton from 'material-ui/lib/flat-button'; 
import CardText from 'material-ui/lib/card/card-text'; 
import Delete from 'material-ui/lib/svg-icons/action/delete'; 
import ModeEdit from 'material-ui/lib/svg-icons/editor/mode-edit'; 
import IconButton from 'material-ui/lib/icon-button'; 
import Button from '../UI/Button'; 

class QuestionItem extends Component { 

    renderTags() { 
     return this.props.data.tag.map((tag) => { 
      return (
       <FlatButton label={tag} /> 
      ) 
     }) 
    } 

    renderCompany() { 
     return this.props.data.company.map((company) => { 
      return (
       <FlatButton label={company} /> 
      ) 
     }) 
    } 

    edit =() => { 
     this.props.edit(this.props.data); 
    } 

    delete =() => { 
     this.props.delete(this.props.data._id); 
     console.log(this.props.data._id); 
    } 

    render() { 
     return (
      <Card style={{margin: 50}}> 
       <CardTitle title={this.props.data.text} /> 
       <CardText> 
        {this.props.data.answer} 
       </CardText> 
       <CardActions> 
        { this.renderTags() } 
        { this.renderCompany() } 

        <IconButton onClick={this.delete} style={{float: 'right'}}> 
         <Delete /> 
        </IconButton> 
        <IconButton onClick={this.edit} style={{float: 'right'}}> 
         <ModeEdit /> 
        </IconButton> 
       </CardActions> 
      </Card> 
     ) 
    } 
} 

export default QuestionItem; 

Что я здесь отсутствует?

+0

Я считаю, что вам нужно в конечном итоге отобразить ключ в HTML, и это не похоже, что вы передали его в свой HTML, но просто имеете его на одном элементе. –

ответ

7

Ну, вам нужно выйти из системы data._id и убедиться, что все они уникальны. Или вы можете сделать это:

renderData() { 
    return this.state.data.map((data, index) => { 
    return (
     <QuestionItem key={index} data={data} delete={this.deleteItem} edit-{this.editItem} /> 
    ); 
}); 
} 

Как другой ответ отметил, что другие вызовы на map, которые идут в рендер необходимости установить key опору слишком уникальное значение.

Так что это:

renderTags() { 
    return this.props.data.tag.map((tag) => { 
     return (
      <FlatButton label={tag} /> 
     ) 
    }) 
} 

renderCompany() { 
    return this.props.data.company.map((company) => { 
     return (
      <FlatButton label={company} /> 
     ) 
    }) 
} 

должны стать:

renderTags() { 
    return this.props.data.tag.map((tag, index) => { 
     return (
      <FlatButton key={index} label={tag} /> 
     ); 
    }); 
} 

renderCompany() { 
    return this.props.data.company.map((company, index) => { 
     return (
      <FlatButton key={index} label={company} /> 
     ); 
    }); 
} 

Примечание мы используем index, который является индекс массива. Это в основном как синтетический идентификатор в SQL. Если у вас на самом деле рендеринг уже есть уникальные идентификаторы, лучше использовать их! Например, опорный знак key для тега может быть только тегом - самой строкой. key опоры поддерживает несколько типов:

react - nodes-and-elements:

key : string | boolean | number | null,

Так что, если ваши метки являются уникальными (я бы ожидать, что они буду, но, очевидно, не хочу брать на себя), вы могли бы сделать это:

renderTags() { 
    return this.props.data.tag.map((tag) => { 
     return (
      <FlatButton key={tag} label={tag} /> 
     ); 
    }); 
} 

Вы могли бы рассмотреть вместо делать что-то вроде (tag || '').toLowerCase().replace(' ', '_') однако я думаю, что React уже делает некоторые манипуляции там (помимо потенциально характера дела). Так что просто прохождение самого тега должно быть хорошим! Вы можете проверить DOM, чтобы увидеть data-reactid, если вы не используете версию, которая избавилась от нее (я думаю, что 0,15 избавится от нее). Инструменты разработчика React могут позволить вам проверить ключ с помощью 0,15.

Update

Я не рекомендую использовать индекс массива в качестве ключа. Это вызывает тонкие ошибки. Чтобы увидеть это в действии, создайте массив объектов, сделайте их с помощью индекса массива и затем измените массив, удалив, скажем, второй элемент (и снова убедитесь, что React renders). Теперь индексы не соответствуют тем же объектам. Моя рекомендация - всегда устанавливать ключ в уникальное значение. Во время разработки лучше всего не устанавливать ключ до тех пор, пока вы его не найдете, а не используете индекс массива, потому что ошибки на консоли напоминают вам об этом, прежде чем приступать к выполнению или совершать изменения.

+0

Обратите внимание, что ошибка говорит 'проверка метода рендеринга QuestionItem'. – Mathletics

+0

@Mathletics Hrm .. разве вы не получите более полезную ошибку на консоли JS? – Cymen

+0

Спасибо за отличное объяснение – erichardson30

2

В renderTags() и renderCompany() у вас есть итераторы без ключей.

+0

Спасибо @mathletics Я пропустил это – erichardson30