1

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.

KenwaySharma
  • 177
  • 1
  • 1
  • 11
  • 1
    it looks right. is `_id` undefined maybe? – azium Oct 15 '20 at 12:31
  • 2
    In your CreateArticle.js you are not setting the `key` attribute for the `option`s generated by `category.map( cat => { ... })` – secan Oct 15 '20 at 12:41
  • When using Stack Snippets, it's a good idea to click "Run code snippet" to see if it demonstrates anything interesting. If not, you should consider using the code formatting button (looks like `{}`) instead. – Heretic Monkey Oct 15 '20 at 14:20
  • Thanks, Secan I rectified it and that error is gone however the one in ArticleCard.js i still have the error. 1 error down. 1 to go. – KenwaySharma Oct 15 '20 at 15:03
  • The second error is probably due to the fact that you fetch the posts with an async operation and you try to map through `posts.postAll` whet it still contains just `[{}]` therefore `post._id` is undefined. I am going to post a fix in the answers, as there is no space in the comments. ;) – secan Oct 15 '20 at 16:20

3 Answers3

1

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>
  • Thanks for replying. 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 – KenwaySharma Oct 15 '20 at 14:59
  • About the other one in the category.map, I assigned the ID to be the same value as the string in my useState as they are all unique. – KenwaySharma Oct 15 '20 at 15:01
0

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

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • Thanks for replying. 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 – KenwaySharma Oct 15 '20 at 14:59
0

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>
...
secan
  • 2,622
  • 1
  • 7
  • 24