Warning: Each child in a list should have a unique "key" prop. Even after setting the key already

882 Views Asked by At

I'm using react in front-end and node, express and mongoose in backend.

I have already made a key={uniqueid} in the files but still I'm getting the error.

Here is the full error(s):

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

Check the render method of `ArticleCard`. See  for more information.
    in div (at ArticleCard.js:34)
    in ArticleCard (at Blog.js:24)
    in div (at Blog.js:22)
    in div (at Blog.js:21)
    in Blog (created by Context.Consumer)
    in Route (at App.js:44)
    in Switch (at App.js:38)
    in AuthContextProvider (at App.js:35)
    in Router (created by BrowserRouter)
    in BrowserRouter (at App.js:34)
    in div (at App.js:32)
    in App (at src/index.js:9)
    in StrictMode (at src/index.js:8)
    
index.js:1 Warning: Each child in a list should have a unique "key" prop.

Check the render method of `CreateArticle`. See for more information.
    in option (at CreateArticle.js:92)
    in CreateArticle (created by Context.Consumer)
    in Route (at App.js:42)
    in Switch (at App.js:38)
    in AuthContextProvider (at App.js:35)
    in Router (created by BrowserRouter)
    in BrowserRouter (at App.js:34)
    in div (at App.js:32)
    in App (at src/index.js:9)
    in StrictMode (at src/index.js:8)

Here is the ArticleCard.js:

import React, { Component, useState, useEffect} from 'react';
import Cookies from 'js-cookie';
import '../components/CSS/ArticleCard.css'
import { Link, Redirect } from 'react-router-dom';
const axios = require('axios').default;

const ArticleCard = () => {
  const [posts, setPosts] = useState({
    postAll: [{}]
  })

  useEffect(() => {
    axios.get('http://localhost:2000/apiEndpoint/READ')
      .then(res => {
        setPosts({ ...posts,
          postAll: res.data
        })
      })
  }, [])

  const articles = posts.postAll.map(post => {
    const uniqueID = post._id
    return (
      <div key={uniqueID} className='card'>
        <h3>{post.title}</h3>
        <hr/>
        <h4>{post.body}</h4>
        <Link className='button' to={`/blog/page/${uniqueID}`}>Open</Link>
      </div>
    )
  })

  return ( 
    <div className='cardContainer'>
    {
      articles > 0 ? "NO" : articles
    }
    </div>
  )
}

export default ArticleCard

Here is the CreateArticle.js:

import { useState } from "react";
import React from 'react';
import axios from 'axios'
import '../CSS/CreateArticle.css'

const CreateArticle=()=>{
    const newData={
        title: '',
        body:'',
        category:'',
        success:'',
        fail:''
    }

    const [data, setData] = useState(newData);
    const [response, setResponse] = useState(newData);
    const [category,setCategory] = useState(['Fashion', 'Food', 'Travel', 'Music', 'Lifestyle', 'Fitness', 'DIY', 'Sports', 'Finance', 'Politics', 'Parenting'])

    const handleSubmit=async (e)=>{
        e.preventDefault()
        await axios.post('http://localhost:2000/apiEndpoint/CREATE', {
            title: data.title,
            body: data.body,
            category:data.category
          },{withCredentials:true},{
            headers: {
                  'Content-Type': 'application/json'
          }})
          .then(function (res) {
            
            if(res.data==='Post Added'){
                console.log('Success:',res)
                setResponse({...response, title:'', body:'',category:'',success: "Post Sucessfully Added"})
                
            }else if(res.data==='JWT authentication failed'){
                setResponse({...response, title:'', body:'',category:'',fail: "You need to login before creating a new post"})
            }else{
                console.log('Erorr', res)
                setResponse({...response, title:res.data.error.title, body:res.data.error.body,category:res.data.error.category,success:''})
            }
            
          })

    }

    const handleChange=(e)=>{
        const {name,value}=e.target
        setData({ ...data, [name]: value });
        
    }
    
    
    return(
        <div className='ninetyPer'>
            <div className='flexit'>
                <h1>Create Post</h1>
                {response.success?(<h5 className='success'>{response.success}</h5>):''}
                {response.fail?(<h5 className='err'>{response.fail}</h5>):''}
                
            <form onSubmit={handleSubmit}>
                <div className='Container'>
                <div className='inputField'>
                        
                        <input name='title' onChange={handleChange} value={data.title} placeholder='Title'></input>
                        {response.title?(<h5 className="err">{response.title}</h5>):''}
                </div>

                <div className='bodyField'>
                    
                    <textarea
                        name='body'
                        onChange={handleChange}
                        value={data.body}
                        placeholder='Write anything'
                    />
                    {response.body?(<h5 className="err">{response.body}</h5>):''}
                </div>
                <div className='selectField'>
                
                <select name='category' value={data.category} onChange={handleChange}>
                    <option value=''>~None Selected~</option>
                    {category.map(cat=>{
                        return(
                            <option value={cat}>{cat}</option>
                            
                        )
                    })
                }
                    
                </select>
                {response.category?(<h5 className="err">{response.category}</h5>):''}
                </div>
                </div>
                <button className='submitBtn'>Submit</button>
                

            </form>
            </div>
        </div>

    )
}

export default CreateArticle

If you require any other file to find the issue, I will update my post with it.

Update: I checked with console.log(uniqueID). At first, it gives me UNDEFINED but the other time it gives the ID. I don't know why exactly does it have UNDEFINED at first even though I checked the data in the DB and they all have separate unique IDs.

3

There are 3 best solutions below

0
On BEST ANSWER

File ArticleCard.js

option 1:

import React, { useState, useEffect, useMemo } from 'react';
import Cookies from 'js-cookie';
import '../components/CSS/ArticleCard.css'
import { Link, Redirect } from 'react-router-dom';

const axios = require('axios').default;

const ArticleCard = () => {
  const [posts, setPosts] = useState({
    postAll: [] // remove the empty object from the state initialization
  });

  useEffect(() => {
    axios.get('http://localhost:2000/apiEndpoint/READ')
      .then(res => {
        setPosts({
          ...posts,
          postAll: res.data
        })
      })
  }, [])
    
  /*
   * check whether there are posts; if not, 'articles' will be null
   * NOTE: useMemo aim is to avoid recalculating 'articles' at each re-render
   *       unless 'posts.postAll' has changed.
   */
  const articles = useMemo(() => {
    if (posts.postAll.length === 0) return null;
    
    return posts.postAll.map(post => {
      const uniqueID = post._id;
      return (
        <div key={uniqueID} className='card'>
          <h3>{post.title}</h3>
          <hr />
          <h4>{post.body}</h4>
          <Link className='button' to={`/blog/page/${uniqueID}`}>Open</Link>
        </div>
      );
    });
  }, [posts.postAll]);

  return (
    <div className='cardContainer'>
        {articles ? articles : "NO"}
    </div>
  );
}

export default ArticleCard;

option 2: get rid of the 'articles' const

import React, { useState, useEffect } from 'react';
import Cookies from 'js-cookie';
import '../components/CSS/ArticleCard.css'
import { Link, Redirect } from 'react-router-dom';

const axios = require('axios').default;

const ArticleCard = () => {
  const [posts, setPosts] = useState({
    postAll: [] // remove the empty object from the state initialization
  });

  useEffect(() => {
    axios.get('http://localhost:2000/apiEndpoint/READ')
      .then(res => {
        setPosts({
          ...posts,
          postAll: res.data
        })
      })
  }, [])

  return (
    <div className='cardContainer'>
        {posts.postAll.length === 0 ? "NO" : (
        posts.postAll.map(post => {
          const uniqueID = post._id;
          return (
            <div key={uniqueID} className='card'>
              <h3>{post.title}</h3>
              <hr />
              <h4>{post.body}</h4>
              <Link className='button' to={`/blog/page/${uniqueID}`}>Open</Link>
            </div>
          );
        });
      )
    </div>
  );
}

export default ArticleCard;

File CreateArticle.js

...
<select name='category' value={data.category} onChange={handleChange}>
  <option value=''>~None Selected~</option>
    {category.map(cat=>{
      return (
        <option key='add_the_key_here' value={cat}>{cat}</option>
      );
    })}
</select>
...
2
On

I think that problem is const uniqueID = post._id. You must print (console.log(post._id)) to see this value is not null or not repeat. Also in:

<select name='category' value={data.category} onChange={handleChange}>
  <option value=''>~None Selected~</option>
     {category.map(cat=>{
        return(
           <option value={cat}>{cat}</option>
        )
      })
  }

you need to specify a key value

 <option key={[uniquevalue]} value={cat}>{cat}</option>
1
On

In ArticleCard.js use console.log(uniqueID) to check if id has any value or it shows undefined.

If value shows undefined then try to check the code from where you are passing that ID.

If uniqueID shows some value then there maybe two possibility check the ID doesn't match with other one, or if you're using any delete post option

If its collapse while adding post after deleting any post then check if you're incrementing ID if yes there may be possibility that ID match will already exist one