简体   繁体   中英

Warning: Each child in a list should have a unique "key" prop. - ReactJS

I'm building a kanban application with ReactJS whereby the user can add a 'card' to three different 'columns' (Todos, Onprogress, & Done). The problem I'm experiencing is that the content that should be displayed in the cards isn't being displayed as it should, although my state is returning its objects just fine (when I console.log everything). I think the problem is that I'm pushing an object into an array and then adding that as a value to one of my keys in state, and because of this my data isn't being read correctly when I pass it down with props. I will share all my code base below.

This is my App Component:

 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;

This is my column component:

 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;

This is my Card Component:

 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;

And this my AddCardForm Component:

 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;

Everywhere you are using a loop to build react components you must add the prop key and pass it a unique value.

You can redefine your map calls to contain the index like this:

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

From the react documentation:

Keys help React identify which items have changed, are added, or are removed. Keys should be given to the elements inside the array to give the elements a stable identity

So, essentially if you are mapping an array to components, having a unique key to every component(mapped ones) will make sure that those components are re-rendered only when necessary.

Please follow this documentation and you will understand what the warning wanted to tell you in-depth.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM