Samoila Andrei
Samoila Andrei

Reputation: 348

How to get rid of the this warning: "Warning: validateDOMNesting(...)"?

I am trying to implement a functional component in my react app: https://gist.github.com/andreisamoila74/bca55271c3992c079eed018e5c95a1be And these are the warnings:

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

Check the render method of `ViewCode`
    in Fragment
    in ViewCode (at App.js:87)
    in Route (at App.js:86)
    in Switch (at App.js:72)
    in main (created by Basic)
    in Basic (created by Context.Consumer)
    in Content (at App.js:71)
    in section (created by Context.Consumer)
    in BasicLayout (created by Context.Consumer)
    in Layout (at App.js:68)
    in App (at src/index.js:13)
    in Router (created by BrowserRouter)
    in BrowserRouter (at src/index.js:12)
    in Suspense (at src/index.js:11)
Warning: validateDOMNesting(...): <tr> cannot appear as a child of <div>.
    in tr (at View.js:49)
    in div (at View.js:48)
    in tbody (at View.js:93)
    in table (at View.js:92)
    in section (created by Context.Consumer)
    in BasicLayout (created by Context.Consumer)
    in Layout (at View.js:91)
    in div (at View.js:90)
    in ViewCode (at App.js:87)
    in Route (at App.js:86)
    in Switch (at App.js:72)
    in main (created by Basic)
    in Basic (created by Context.Consumer)
    in Content (at App.js:71)
    in section (created by Context.Consumer)
    in BasicLayout (created by Context.Consumer)
    in Layout (at App.js:68)
    in App (at src/index.js:13)
    in Router (created by BrowserRouter)
    in BrowserRouter (at src/index.js:12)
    in Suspense (at src/index.js:11)
Warning: validateDOMNesting(...): <div> cannot appear as a child of <tbody>.
    in div (at View.js:48)
    in tbody (at View.js:93)
    in table (at View.js:92)
    in section (created by Context.Consumer)
    in BasicLayout (created by Context.Consumer)
    in Layout (at View.js:91)
    in div (at View.js:90)
    in ViewCode (at App.js:87)
    in Route (at App.js:86)
    in Switch (at App.js:72)
    in main (created by Basic)
    in Basic (created by Context.Consumer)
    in Content (at App.js:71)
    in section (created by Context.Consumer)
    in BasicLayout (created by Context.Consumer)
    in Layout (at App.js:68)
    in App (at src/index.js:13)
    in Router (created by BrowserRouter)
    in BrowserRouter (at src/index.js:12)
    in Suspense (at src/index.js:11)

I understand each warning, but I am not sure how I can get rid of its. Regarding the table, I need those divs so my AddComment component is placed in the right way. How should I solve this? Thanks :)

Upvotes: 1

Views: 623

Answers (3)

Samoila Andrei
Samoila Andrei

Reputation: 348

I solved it this way:

rows.push(
  <React.Fragment key={index}>
    <tr key={index} className="line">
      <td className="line-number">{index + 1}</td>
      <td id={"plus" + index} className="plus-square-line">
        <PlusSquareTwoTone className="plus-square"
          onClick={() => toggleLineCommentStatus(index + 1)} />
      </td>
      <td id={"codeblock" + index}
        className={'language-' + codeLanguage} style={rowStyle}>
        {line}
      </td>
    </tr>
    <tr>
      <td></td>
      <td></td>
      <td>
        {lineComments[index + 1]
          ?
          <AddComment
            id={id}
            lineNumber={index + 1}
            onCancelLineCommentShow={toggleLineCommentStatus}
          />
          :
          null
        }
      </td>
    </tr>
  </React.Fragment>
);

thanks for answers

Upvotes: 0

Drew Reese
Drew Reese

Reputation: 202721

The react keys need to be declared on the outer-most element mapped. In your case, the Fragment, or rather, the div since the Fragment isn't doing much for you.

The second error: "validateDOMNesting(...): cannot appear as a child of " is saying the tr can't be a child of the div.

You can still use a Fragment though for both the purpose of returning a single node and provide the react key.

data.code.source_code.split("\n").forEach((line, index) => {
  rows.push(
    <Fragment key={index}> // <-- attach react key to Fragment
      <tr className="line">
        <td className="line-number">{index + 1}</td>
        <td id={"plus" + index} className="plus-square-line">
          <PlusSquareTwoTone
            className="plus-square"
            onClick={() => toggleLineCommentStatus(index + 1)}
          />
        </td>
        <td
          id={"codeblock" + index}
          className={"language-" + codeLanguage}
          style={rowStyle}
        >
          {line}
        </td>
      </tr>
      <div style={divStyle}>
        {lineComments[index + 1] ? (
          <AddComment
            id={id}
            lineNumber={index + 1}
            onCancelLineCommentShow={toggleLineCommentStatus}
          />
        ) : null}
      </div>
    </Fragment>
  );
});

Upvotes: 1

IvanD
IvanD

Reputation: 2923

When you create an array of children, like on row 46, each of them need to have a key prop.

If you don't have it, there is no way for React to know how the new and the old arrays are different, so it has to rerender all children, which is a performance drag. With key prop, it checks for new or deleted children by comparing keys from the new and old arrays of children.

You can read about it here https://kentcdodds.com/blog/understanding-reacts-key-prop

Upvotes: 0

Related Questions