警告:列表中的每个孩子都应该有一个唯一的“关键”道具。 -ReactJS

时间:2019-07-29 16:53:16

标签: javascript arrays reactjs javascript-objects

我正在用ReactJS构建看板应用程序,以便用户可以向三个不同的“列”(Todos,Onprogress和完成)添加“卡片”。我遇到的问题是,尽管我的状态返回的对象很好(当我用console.log记录所有内容时),但应该在卡中显示的内容却没有得到应有的显示。我认为问题在于,我正在将一个对象推入数组中,然后将其作为值添加到状态中的一个键中,因此,当我使用prop传递数据时,无法正确读取我的数据。我将在下面共享我的所有代码库。

这是我的应用程序组件:

import React, { Component } from 'react';
  import Column from './Column';
  import AddCardForm from './AddCardForm';
  import './App.css';

class App extends Component {
    constructor(props) {
      super(props)
      this.state = {
        columns: [
          {
            name: 'Todos',
            cards: []
          },
          {
            name: 'Onprogress',
            cards: []
          },
          {
            name: 'Done',
            cards: []
          }, 
        ] 
      };
    };

    // componentDidMount() {
    //   const { coldata } = this.state.columns
    //   console.log(coldata);
    //   // this.ref = base.syncState();
    // }

    addCard = (card, otherStatus) => {
      console.log("Adding a Card");
      const cards = { ...this.state.columns.cards };
      cards[`card`] = card;
      
      let todosCards = []
      let onprogressCards = []
      let doneCards = []
      
      Object.values(otherStatus).map(function(value) {
        if (value.includes('Onprogress') && value.includes('Done')) {
              todosCards.push(cards)
        } else if (value.includes('Todos') && value.includes('Done')) {
              onprogressCards.push(cards);
        } else if (value.includes('Todos') && value.includes('Onprogress')) {
              doneCards.push(cards);
        }
        return(todosCards || onprogressCards || doneCards);  
      });

      console.log(todosCards);
      console.log(onprogressCards);
      console.log(doneCards);

        this.setState({
          columns: [
            { 
              name: 'Todos',
              cards: todosCards
            },
            { 
              name: 'Onprogress',
              cards: onprogressCards
            },
            { 
              name: 'Done',
              cards: doneCards
            },
          ] 
        });
    }
        
  render() {
    return (
  <div className="App">
   {Object.keys(this.state.columns).map(key => (
      <Column key={key} details={this.state.columns[key]} />
    ))}
      <AddCardForm addCard={this.addCard} />
  </div>
    );
  }
}
export default App;

这是我的列组件:

import React, {Component} from "react";
import Card from "./Card"


class Column extends Component {
    render() {
        return (
        <div className="column"> 
            <h1 className="Title">{this.props.details.name}</h1>
            {Object.keys(this.props.details.cards).map( keycard => (
                <Card keycard={keycard} data={this.props.details.cards[keycard]} /> 
            ))}     
        </div>
        );
    }
}

export default Column;

这是我的卡组件:

    import React, {Component} from "react";


    class Card extends Component {
        render() {
            const {taskName, taskDescription, taskPeriod } = this.props.data;
            // const isTaskOn = taskStatus 
            return (
            <div className="card">
                <span className="title">{taskName}</span>
                <div className="description">
                    <h4>{taskDescription}</h4>
                </div>
                <div className="period">
                    <h4>{taskPeriod}</h4>
                </div>
                <div className="status">
                    <select>
                        <option value='Todos'>Todos</option>
                        <option value='Onprogress'>Onprogress</option>
                        <option value="Done">Done</option>
                    </select>
                </div>
            </div>  
            );
        }
    }

    export default Card;

这是我的AddCardForm组件:

import React, { Component } from 'react';


class AddCardForm extends Component {

    taskName = React.createRef();
    taskDescription = React.createRef();
    taskPeriod = React.createRef();
    taskStatus = React.createRef(); 

    addCardtoApp = event => {
        event.preventDefault();
        const card = {
            taskName: this.taskName.current.value, 
            taskDescription: this.taskDescription.current.value,
            taskPeriod: this.taskPeriod.current.value,
        };
        const cardStatus = this.taskStatus.current.value;
        let otherStatus = {
            otherStatus: this.taskStatus.current.textContent.replace(`${cardStatus}`, ''),
        };
        
        this.props.addCard(card, otherStatus);
        event.currentTarget.reset();
    };
    
    render() {
        return (
        <form onSubmit={this.addCardtoApp}>
        <label>
            Task Name:
            <input type="text" name="taskName" ref={this.taskName}/>
        </label> <br />
        <label>
            Description:
            <input type="text" name="taskDescription" ref={this.taskDescription} />
        </label> <br /> 
        <label>
            Period:
            <input type="text" name="taskPeriod" ref={this.taskPeriod} />
        </label> <br />
        <label>
            Task Status:
            <select type="text" name="taskStatus" ref={this.taskStatus}>
                <option value="Todos">Todos</option>
                <option value="Onprogress">Onprogress</option>
                <option value="Done">Done</option>
            </select>
        </label> <br />
        <input type="submit" value="Submit" />
        </form>
        );
    }
}

export default AddCardForm;

2 个答案:

答案 0 :(得分:1)

在使用循环构建反应组件的每个地方,都必须添加prop key并为其传递一个唯一值。

您可以重新定义map调用以包含如下所示的索引:

Object.keys(this.state.columns).map((count, key) => (
    <Column key={count} details={this.state.columns[key]} />
))

答案 1 :(得分:0)

从react文档中:

  

键可帮助React识别哪些项目已更改,添加或删除。应该为数组内的元素赋予键,以赋予元素稳定的身份

因此,从本质上讲,如果您要将数组映射到组件,则对每个组件(映射的组件)都有唯一的键将确保仅在必要时才重新渲染这些组件。

请按照this documentation进行操作,您将了解该警告想向您详细介绍的内容。