Home > Blockchain >  Each child in a list should have a unique "key" prop. still even after assgining a key
Each child in a list should have a unique "key" prop. still even after assgining a key

Time:03-26

Just I have been fiddling with ReactJs and ASP.net core and I am wondering why it throws an error that each component should have a key and when I have modified my code to assign a key it keeps displaying the same messagem how could I solve it?

react.development.js:401 Warning: Each child in a list should have a unique "key" prop.

Check the render method of CommentBox. See https:// fb . me/react-warning-keys for more information. in label (created by CommentBox) in CommentBox


class CommentBox extends React.Component {
    render() {
        const span = React.createElement('span', { className: "span" }, 'First Component React');
        const label = React.createElement('label', { className: "label" }, span);
        const brTag = React.createElement('br')
        const textBox = React.createElement('input', { className: "input", placeholder: "Hola" });
        const upperDiv = React.createElement('div', { key:"upperDivinput", className: "div" }, [label, brTag, textBox]);

        let comments = [];
        let baseUrl = 'https://localhost:44379';
        let endPointComments = '/Posts/GetComments';
        baseUrl = baseUrl   endPointComments;
        fetch(baseUrl)
            .then(response => response.json())
            .then(result => {
                comments = result;
                console.log(result);
            });
        let commentsParagraph = [];
         for (let i = 0; i < comments.length; i  ) {
            console.log(comments[i].author);
            const paragItemTitle = React.createElement('p', { key:'author_${i}' ,className: "p" }, comments[i].author);
            const paragraphItemText = React.createElement('p', { key: 'comment_${i}', className: "p" }, comments[i].text);
            commentsParagraph.push(paragItemTitle);
            commentsParagraph.push(paragraphItemText);
        }
        const lowerDiv = React.createElement('div', { key:"lowerDivComments", className: 'div' }, commentsParagraph);
        const wrapperOuter = React.createElement('div', { key:"wapperDivComments", className:"div" }, [upperDiv, lowerDiv])
        return wrapperOuter;
            
        
    }
}

ReactDOM.render(<CommentBox />, document.getElementById('root'));

CodePudding user response:

Yes, you should use functional components instead of class components. componentWillMount() can then be replaced by the useEffect() hook. And you should consider using JSX as this is way easier to read then your lengthy createElement() calls. Probably best for you to start with the official React guide.

As I've mentioned in my comment use ` (=backticks) for string literals. And try to avoid using an index as a key as an index is not stable.

Here a small example of a similar component as the one you want to build that uses string literals, a good key, a functional component and an API request to request some data. Click this link to see the dummy data that is returned by the API.

function CommentBox() {
  const [comments, setComments] =  React.useState([]);

  React.useEffect(() => {
    const url = "https://gorest.co.in/public/v2/comments";
    const response = fetch(url).then(resp => resp.json().then(json => setComments(json)));
  }, []);

  return (
    <ul>
      {comments.map((comment) => (
        <li>
          <span>{`Comment No. ${comment.id} from ${comment.name}`}</span>
          <blockquote>{comment.body}</blockquote>
        </li>
      ))}
    </ul>
  );
}

ReactDOM.render(<CommentBox />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Unfortunately I cannot use async/ await when using React on StackOverflow as I have to tick Babel/ ES2015 within my snippet. Usually I would use an async function in useEffect() and use await instead of chaining then().

The useEffect() hook would then look like this. Both versions result in the same output though.

React.useEffect(async () => {
    const url = "https://gorest.co.in/public/v2/comments";
    const response = await fetch(url);
    const data = await resp.json();
    setComments(data);
  }, []);

Please note: you would still need to implement some error handling here.

CodePudding user response:

The problem is kind of hidden with this kind of code: [label, brTag, textBox] and [upperDiv, lowerDiv].

Any time you have an array of elements, every element in that array must have a key. In this case, your label, brTag, and textBox need a key.

Also, you never want to do things like API requests inside your render function. Please use the lifecycle hooks like componentDidMount for loading data, and calling setState to trigger a new render. DO NOT call setState inside your render method.

Also, do yourself and everybody else a favor and use JSX. It's compiled a build time (not run time), so it doesn't cost you any performance and is much easier to read (note: this advice is coming from someone who initially resisted JSX). In such case, you could use react fragments and avoid having to define unnecessary keys:

<>
  <label>...</label>
  <br />
  <input ... />
</>
  • Related