React error: Each child in a list should have a unique "key" prop

263 Views Asked by At

this is my code in 2 components and index.tsx,

NewsFeed.tsx

import React, { useState } from 'react'
import Feeds from './Feeds'



export default function NewsFeed({ news }: any) {
   
  const [date, setDate] = useState(new Date())
  
  return (
    <div className='bg-white'>
      <div className='flex justify-between p-4'>
        <h1>Wellcome to clone BBC.com</h1>
        <h1>{date.toDateString()}</h1>
      </div>
      
         {news.articles.slice(0, 1).map((article: any) => (
          <a key={article.id} href={article.url}
            className="relative">
            <img key={article.id} className='w-full' src={article.urlToImage ? article.urlToImage: "./ALT.jpg"} alt="" />
            <h1 key={article.id}
             className='text-white absolute bottom-[40%] left-[5%]
             lg:text-2xl text-xl'>{article.title}</h1>
             <p key={article.id} className='text-white absolute bottom-[30%] left-[5%] line-clamp-1'>{article.description}</p>
          </a>
          ))}
        <div className='grid grid-flow-row-dense md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4'>{/*grid start*/}
        {news.articles.slice(1, news.articles.length).map((article: any) => (
          <Feeds
           url={article.url}
           className=""
           key={article.id}
           urlToImage={article.urlToImage}
           title={article.title}
           description={article.description}
          />
        ))}
      </div>
      
    </div>
  )
}

Feeds.tsx


import React from 'react'


export default function Feeds({title, urlToImage, description, url}: any) {
    const altImg = "/ALT.jpg"
    const handleError = (e: any) => {
      e.target.src = altImg
    }
  return (
    <a className='px-3 py-6 my-3' href={url}>
       <img 
         src={!urlToImage ?  "/ALT.jpg" : urlToImage}
         onError={handleError} 
         height={300} width={300} alt="cover_image" />
         <h2 className='text-lg'>{title}</h2>
         <p className='line-clamp-1'>{description}</p>
    </a>
  )
}

index.tsx

import Head from 'next/head'
import Header from '../components/Header';
import NewsFeed from '../components/NewsFeed';

export default function Home({ news }: any) {
  return (
    <div className='bg-gray-100 '>
      <Head>
        <title>Create Next App</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <Header />
      <main className='mx-5 my-5'>
        <NewsFeed news={news} key={news.article}/>
      </main>
    </div>
  )
}


export async function getServerSideProps(context: any) {
  
  const news = await fetch("https://newsapi.org/v2/top-headlines?country=us&category=business&apiKey=a252437b389346d0b79f7417e0ca9e30")
   .then(res=>res.json());

  return {
    props: {
      news,
    }
  }
}

next-dev.js?3515:20 Warning: Each child in a list should have a unique "key" prop.

Check the render method of NewsFeed. See https://reactjs.org/link/warning-keys for more information. at Feeds (webpack-internal:///./components/Feeds.tsx:13:11) at NewsFeed (webpack-internal:///./components/NewsFeed.tsx:15:11) at main at div at Home (webpack-internal:///./pages/index.tsx:18:11) at SessionProvider (webpack-internal:///./node_modules/next-auth/react/index.js:478:24) at App (webpack-internal:///./pages/_app.tsx:15:11) at PathnameContextProviderAdapter (webpack-internal:///./node_modules/next/dist/shared/lib/router/adapters.js:62:11) at ErrorBoundary (webpack-internal:///./node_modules/next/dist/compiled/@next/react-dev-overlay/dist/client.js:301:63) at ReactDevOverlay (webpack-internal:///./node_modules/next/dist/compiled/@next/react-dev-overlay/dist/client.js:850:919) at Container (webpack-internal:///./node_modules/next/dist/client/index.js:60:1) at AppContainer (webpack-internal:///./node_modules/next/dist/client/index.js:173:11) at Root (webpack-internal:///./node_modules/next/dist/client/index.js:346:11)

I have tried to give a unique key to each child but nothing worked what I'm missing?

2

There are 2 best solutions below

1
Yury Tarabanko On

Keys must be unique. Check this piece of code

          <a key={article.id} href={article.url}
            className="relative">
            <img key={article.id} className='w-full' src={article.urlToImage ? article.urlToImage: "./ALT.jpg"} alt="" />
            <h1 key={article.id}
             className='text-white absolute bottom-[40%] left-[5%]
             lg:text-2xl text-xl'>{article.title}</h1>
             <p key={article.id} className='text-white absolute bottom-[30%] left-[5%] line-clamp-1'>{article.description}</p>
          </a>

Here you have 3 children of a (img, h1, and p) having the same key. Just remove it.

          <a key={article.id} href={article.url}
            className="relative">
            <img className='w-full' src={article.urlToImage ? article.urlToImage: "./ALT.jpg"} alt="" />
            <h1 className='text-white absolute bottom-[40%] left-[5%]
             lg:text-2xl text-xl'>{article.title}</h1>
             <p className='text-white absolute bottom-[30%] left-[5%] line-clamp-1'>{article.description}</p>
          </a>

Also check other pieces of code of having the same issue.

2
Snehal On

In the following code of lines the same key of article.id is being assigned to each tag present under single map method:

{news.articles.slice(0, 1).map((article: any) => (
      <a key={article.id} href={article.url}
        className="relative">
        <img key={article.id} className='w-full' src={article.urlToImage ? article.urlToImage: "./ALT.jpg"} alt="" />
        <h1 key={article.id}
         className='text-white absolute bottom-[40%] left-[5%]
         lg:text-2xl text-xl'>{article.title}</h1>
         <p key={article.id} className='text-white absolute bottom-[30%] left-[5%] line-clamp-1'>{article.description}</p>
      </a>
      ))}

Hence try to make the key unique as follows: Solution1:

{news.articles.slice(0, 1).map((article: any) => (
      <a key={"a"+article.id} href={article.url}
        className="relative">
        <img key={"img"+article.id} className='w-full' src={article.urlToImage ? article.urlToImage: "./ALT.jpg"} alt="" />
        <h1 key={"h1"+article.id}
         className='text-white absolute bottom-[40%] left-[5%]
         lg:text-2xl text-xl'>{article.title}</h1>
         <p key={"p"+article.id} className='text-white absolute bottom-[30%] left-[5%] line-clamp-1'>{article.description}</p>
      </a>
      ))}

Or if you can generate an unique key by any other way, that will also work.

Or

Solution 2: Ideally there is no need to provide key to each and every tag under the map method, it's sufficient to provide key to the most parent tag (anchor tag in your case). Please refer the following solution for an example:

{news.articles.slice(0, 1).map((article: any) => (
      <a key={article.id} href={article.url}
        className="relative">
        <img className='w-full' src={article.urlToImage ? article.urlToImage: "./ALT.jpg"} alt="" />
        <h1
         className='text-white absolute bottom-[40%] left-[5%]
         lg:text-2xl text-xl'>{article.title}</h1>
         <p className='text-white absolute bottom-[30%] left-[5%] line-clamp-1'>{article.description}</p>
      </a>
      ))}