0

I am making a test news app with infinite scroll react but when I scroll for more news I got the same news that I have seen above and get the error in console like:

react-dom.development.js:67 Warning: Encountered two children with the same key, https://www.nytimes.com/2022/04/01/movies/oscars-will-smith-slap.html. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version. at div at div at div at div at InfiniteScroll (http://localhost:3000/static/js/bundle.js:35314:24) at New (http://localhost:3000/static/js/bundle.js:590:5) at Routes (http://localhost:3000/static/js/bundle.js:37042:5) at Router (http://localhost:3000/static/js/bundle.js:36975:15) at BrowserRouter (http://localhost:3000/static/js/bundle.js:36451:5) at div at App (http://localhost:3000/static/js/bundle.js:36:5)

The place where I am using the keys is app

import NewsIItem from './NewsIItem'
import InfiniteScroll from 'react-infinite-scroll-component';
import ScrollLoader from './ScrollLoader';
export class New extends Component {

  static defaultProps = {
    category: "general"
  }
  // static propTypes = {
  //   category : PropTypes.string
  // }
  constructor() {
    super();
    this.state = {
      articles: [],
      loading: false,
      page: 1,
      totalResults: 0

    }
  }
  async componentDidMount() {
    // console.log("Inside the cdm");
    let myUrl = `https://newsapi.org/v2/top-headlines?country=us&category=${this.props.category}&apiKey={private}&page=1&pageSize=${this.props.pageSize}`
    let data = await fetch(myUrl)
    let parsedData = await data.json()
    console.log(parsedData);
    this.setState({ articles: parsedData.articles, totalResults: parsedData.totalResults })
  }

  fetchData = async () => {
    this.setState({
      page: this.state.page + 1
    })
    let myUrl = `https://newsapi.org/v2/top-headlines?country=us&category=${this.props.category}&api= {private}&page=1&pageSize=${this.props.pageSize}`
    this.setState({ loading: true })
    let data = await fetch(myUrl)
    let parsedData = await data.json()
    console.log(parsedData);
    this.setState({ articles: this.state.articles.concat(parsedData.articles), totalResults: parsedData.totalResults, loading: false })
  }
  render() {
    return (
      <>

        <h2 className="headlines text-center">Newsers Most updated ~ Headlines</h2>
        <InfiniteScroll
          dataLength={this.state.articles.length} //This is important field to render the next data
          next={this.fetchData}
          hasMore={this.state.articles.length !== this.state.totalResults}
          loader={<ScrollLoader />}
        >
          <div className="container">

            <div className="row my-3">
              {this.state.articles.map((element) => {
                return <div className="col-md-4" key={element.url}>
                  <NewsIItem title={element.title} description={element.description} imageUrl={!element.urlToImage ? "https://i.pinimg.com/originals/d1/a6/2a/d1a62a6d8969170025f279115470e34b.jpg" : element.urlToImage} newsId={element.url} />
                </div>
              })}
            </div>
          </div>
        </InfiniteScroll>


      </>

    )
  }
}

export default New

  • The space does not matter, the issue is the duplicate Route – Ross Apr 01 '22 at 16:35
  • @Ross I doubt it. Unless RRD6 changed more than I'm aware of, `Routes` should only render the first match. The duplicate would never be reached. – Brian Thompson Apr 01 '22 at 16:37
  • @AwaisZahid Can you share the data you are mapping over? Is it possible there is more than one entry with that URL? Is there a more unique value you could be using to identify them? – Brian Thompson Apr 01 '22 at 16:38
  • What is the value of `this.state.articles` that is mapped? Seems there's a duplicate `key={element.url}` value. This value/property/etc needs to be locally unique within the dataset. – Drew Reese Apr 01 '22 at 16:38
  • @DrewReese this.state = { articles: [], loading: false, page: 1, totalResults: 0 } – Awais Zahid Apr 01 '22 at 16:39
  • 1
    No, `this.state.articles` specifically, ***after*** it's populated. – Drew Reese Apr 01 '22 at 16:40
  • @DrewReese brother i am not getting your point but for your ease I have uploaded the whole code check it out – Awais Zahid Apr 01 '22 at 16:42
  • 1
    How about this way - We need to know what's in `parsedData`. Just show us the result of the console.log you have – Brian Thompson Apr 01 '22 at 16:43
  • @BrianThompson I have uploaded the whole code – Awais Zahid Apr 01 '22 at 16:44
  • I just checked `"https://newsapi.org/v2/top-headlines?country=us&category=general&apiKey=XXXX&page=1&pageSize=10"` and don't see any article entires with GUIDs. I suggest augmenting the response data with an `id` property. You also might not want to always append (*i.e. `.concat`*) entries to the state as it doesn't appear you handle duplicate response data. – Drew Reese Apr 01 '22 at 16:45
  • 1
    I think Drew hit part of your problem with `concat`, and I think the other half of the problem is hard coding `&page=1` in your request. You're setting a page in state, you probably are wanting to use it for the next results instead of concatenating the same page of data over and over again. This is probably what's causing your duplicate keys -- actual duplicate data – Brian Thompson Apr 01 '22 at 16:47
  • @BrianThompson brother you are right i replaced the page=1 with this.state.page and it works thanks alot – Awais Zahid Apr 01 '22 at 16:56
  • React state updates are also asynchronously processed, so `fetchData` can't enqueue an update to increment the `this.state.page` value ***and*** use the "updated" page state in the same callback scope. – Drew Reese Apr 01 '22 at 16:56
  • Just so you know, the edit history of Stack Overflow posts is publicly visible... – Ryan M Apr 05 '22 at 06:16

2 Answers2

0

Just update this line of code:

{this.state.articles.map((element) => return <div className="col-md-4" key= 
   {element.url}>

To this

{this.state.articles.map((element,index)=> {
  return <div className="col-md-4" key={index}>    
nima
  • 7,796
  • 12
  • 36
  • 53
-1

Yo have this line twice:

<Route exact path="/sports" element={<New key= "sports" pageSize={this.pageSize} category="sports" />} />

Remove one or change the key values.

ask4you
  • 768
  • 3
  • 14
  • I removed the duplicate line but it doesn't work and how do you want me to change the values – Awais Zahid Apr 01 '22 at 16:32
  • Maybe is this line: `{this.state.articles.map((element) => { return
    ` Try using the index as key like this: `{this.state.articles.map((element,index) => { return
    `
    – ask4you Apr 01 '22 at 16:50