10

I am trying to fix these two warnings:

Warning: validateDOMNesting(...): <td> cannot appear as a child of <tbody>.

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

Here is my table js file:

        <table className="table table-hover">

  <thead>

    <tr>
      <th scope="col"style={{width: "10%"}}>ID</th>
      <th scope="col"style={{width: "10%"}}>Name</th>
      <th scope="col"style={{width: "10%"}}>Price $</th>
      <th scope="col" style={{width: "10%"}}>Quantity</th>
      <th scope="col" style={{width: "10%"}}>Total $:</th>
      <th scope="col" style={{width: "10%"}}>Total €:</th>
      <th scope="col" style={{width: "20%"}}>Remove:</th>
      <th scope="col" style={{width: "20%"}}>Change Quantity:</th>
    </tr>
  </thead>

  {this.state.products.map(data=>
   <tbody>
      <td>{data.id}</td>



      <td>{data.name}</td>


      <td>{data.price}</td>


      <td>{data.quantity}</td>


      <td>{data.quantity*data.price}</td>
      <td>{Math.round(data.quantity*data.price*0.92)}</td>
      <td>
      <button type="button" onClick={(e)=>this.handleSubmitRemove(data.id)} className="btn btn-danger">Remove</button>
      </td>

      <td>
       <button  style={{margin: "3px"}}  type="button" onClick={(e)=> this.updateCart(data.id,1)}>+</button>
       <button  style={{margin: "3px"}} disabled={data.quantity==1} type="button" onClick={(e)=> this.updateCart(data.id,-1)}>-</button>
      </td>

      </tbody>
  )}

</table>

I tried to get <tbody> outside the this.state.products.map(data=> but then I have another error

JSX expressions must have one parent element.

Any help or idea would be appreciated to solve this issue.

Thank you so much! Have a nice day

HardRock
  • 809
  • 2
  • 12
  • 37
  • 1
    RE: `Warning: validateDOMNesting(...): cannot appear as a child of .` - Simply add a row to your `` i.e. `` – developer Apr 29 '20 at 09:29
  • Re : `Warning: Each child in a list should have a unique "key" prop.` change you map from : `this.state.products.map(data=>` to this.state.products.map((data, myKey)=>` then use this key in your `` like this: `` – developer Apr 29 '20 at 09:31
  • Yes it is working. Could you please explain this and post it as answer, for future use. Thank you – HardRock Apr 29 '20 at 09:35
  • glad it worked - ive posted an answer below - with some references. Let me know if you need more information – developer Apr 29 '20 at 09:45

2 Answers2

14

For: Warning: validateDOMNesting(...): <td> cannot appear as a child of <tbody>. - Simply add a row to your <tbody>

i.e.

<tbody><tr><td></td></tr></tbody>

The correct html structure of a table is shown here:

ref: https://www.w3schools.com/tags/tag_tbody.asp

and for: Warning: Each child in a list should have a unique "key" prop.

Change you map from : this.state.products.map(data=> to: this.state.products.map((data, myKey)=> then use this key in your <tbody> like this: <tbody key={myKey}>

React components require a unique key. when using map to generate child components in earlier versions, implementors had to set this. The simplest way to do this is to use the item index from the map function, in the root element of your child.

ref: https://reactjs.org/docs/lists-and-keys.html

<table className="table table-hover">    
  <thead>    
    <tr>
      <th scope="col"style={{width: "10%"}}>ID</th>
      <th scope="col"style={{width: "10%"}}>Name</th>
      <th scope="col"style={{width: "10%"}}>Price $</th>
      <th scope="col" style={{width: "10%"}}>Quantity</th>
      <th scope="col" style={{width: "10%"}}>Total $:</th>
      <th scope="col" style={{width: "10%"}}>Total €:</th>
      <th scope="col" style={{width: "20%"}}>Remove:</th>
      <th scope="col" style={{width: "20%"}}>Change Quantity:</th>
    </tr>
  </thead>

  {this.state.products.map((data, myKey) =>
   <tbody key={myKey}>
     <tr>
      <td>{data.id}</td>
      <td>{data.name}</td>    
      <td>{data.price}</td>    
      <td>{data.quantity}</td>
      <td>{data.quantity*data.price}</td>
      <td>{Math.round(data.quantity*data.price*0.92)}</td>
      <td>
      <button type="button" onClick={(e)=>this.handleSubmitRemove(data.id)} className="btn btn-danger">Remove</button>
      </td>    
      <td>
       <button  style={{margin: "3px"}}  type="button" onClick={(e)=> this.updateCart(data.id,1)}>+</button>
       <button  style={{margin: "3px"}} disabled={data.quantity==1} type="button" onClick={(e)=> this.updateCart(data.id,-1)}>-</button>
      </td>
      </tr>
    </tbody>
  )}

</table>

For more information about this: JSX expressions must have one parent element. See this post: React - expressions must have one parent element?

developer
  • 690
  • 7
  • 16
1

I faced an error which said this:

How to fix validateDOMNesting(…): <th> cannot appear as a child of <thead>. and Each child in a list should have a unique “key” prop.

I finally found out that I was missing <tr></tr> after <thead></thead> tag. So check in your <thead></thead> tag and see whether your other <th></th> tags are enclosed within <tr></tr> tag. Finally your code should look like this:

<thead>
<tr>
<th>
//other content here like <td>
</th>
</tr>
</thead>
Blessing
  • 2,450
  • 15
  • 22