React setState for multiple items

I'm currently working on creating a news app that showcases the top 20 articles from each country. However, I encountered an issue when trying to set my state inside a loop - all entries were being overwritten and only the last one would display. Any suggestions on how I can avoid this problem and show multiple entries without overriding the previous ones? Thank you for your help!

//the code snippet below is located within my App.js file under the App component
getNews = async (e) => {
e.preventDefault();
const country = e.target.elements.country.value;
const api_call = await fetch(this.buildURL(country));
const data = await api_call.json();

if (country) {
console.log(data);

//I modified this section to display the first article out of 20
this.setState({
title: data.articles[0].title,
image: data.articles[0].urlToImage,
description: data.articles[0].description,
author: data.articles[0].author,
link: data.articles[0].url,
err: ""
});
}
else {
this.setState({
title: undefined,
image: undefined,
description: undefined,
author: undefined,
link: undefined,
err: "Please enter a valid country"
});
}


}

render() {
return(
<div>
<Titles />
<Form getNews={this.getNews}/>
<News title={this.state.title}
image={this.state.image}
description={this.state.description}
author={this.state.author}
link={this.state.link}
err={this.state.err}
/>
</div>
);
}

This is a project aimed at beginners so please consider that in your responses haha.

Answer №1

If you're looking to display all news items from a specific state, the process involves fetching the data and mapping over it to create a News element for each item. Here's an example of how you could handle the request:

getNews = async e => {
  e.preventDefault();
  const country = e.target.elements.country.value;
  if (!country) {
    this.setState({
      articles: null,
      err: "Please enter valid country"
    });
  }
  let data;
  try {
    data = await fetch(this.buildURL(country)).then(res => res.json());
  } catch (error) {
    this.setState({
      articles: null,
      err: "Please enter valid country"
    });
  }
  if (data) {
    this.setState({
      articles: data.map(article => ({
        title: article.title,
        image: article.urlToImage,
        description: article.description,
        author: article.author,
        link: article.url
      }))
    });
  }
};

Do keep in mind that there might be bugs lurking!

Once you have all the articles stored in your state, you can loop through them like so:

render() {
  return (
    <div>
      <Titles />
      <Form getNews={this.getNews} />

      {this.state.articles.map(article => (
        <News
          title={article.title}
          image={article.image}
          description={this.state.description}
          author={article.author}
          link={article.link}
          err={article.err}
        />
      ))}
    </div>
  );
}

You could also use object spread to pass props if the keys in your state exactly match those expected by the News component:

  {this.state.articles.map(article => (
    <News {...article}/>
  ))}

Answer №2

It is recommended that your state should be structured as an array rather than just a provision for one object.

this.setState({
    title: data.articles[0].title,
    image: data.articles[0].urlToImage,
    description: data.articles[0].description,
    author: data.articles[0].author,
    link: data.articles[0].url,
    err: ""
});

A better approach would be to update it in the following manner:

var articles = this.state.articles.slice();
var newArticle = {
    title: data.articles[0].title,
    image: data.articles[0].urlToImage,
    description: data.articles[0].description,
    author: data.articles[0].author,
    link: data.articles[0].url,
    err: ""
};
articles.push(newArticle);

this.setState(articles);

Additionally, keep in mind that setState is asynchronous. Thus, at times, you may need to utilize the current state to determine the new value of the state. Refer to the setState documentation for more information.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to retrieve the parent iFrame ID when a blur event occurs in the TinyMCE

I have successfully implemented 4 TinyMCE editors on a single page. My goal is to obtain the editor ID when the user exits the TinyMCE editor and place the editor's HTML content into a textarea. While I can achieve this using the blur event in Chrome, ...

Exploring the ins and outs of webpage loading speed

I am working on writing JavaScript code that includes a button to open a webpage of my choice. I now want to understand how to detect when the page I called is finished loading. Any suggestions or ideas on this topic? I apologize if my explanation was no ...

Is it possible to display the details of a chosen listitem on a separate activity using JSON data?

When I display a list item in my activity, I only want to show the name of places. However, when I click on an item, I want to show the details related to that place name in another activity called location detail. I am new to Android and would appreciate ...

Exporting items with a label in TypeScript/JavaScript

Is it possible to rename the functions that are exported using the following syntax in Typescript/Javascript? export const { selectIds, selectEntities, selectAll, selectTotal } = adapter.getSelectors(selectState); I would like to import selectAll as sele ...

What is the best way to integrate ChartJS with a background color in the gap area separating two line charts?

Is it possible to create a unique 2 line chart with filled in space between the lines using ChartJS? https://i.sstatic.net/8hXRd.png The chart will display time on the X axis and min & max temperature on the Y axis at each sample. Only the area betw ...

Implement a FOR loop in conjunction with an AJAX request

My goal is to send an AJAX request with multiple form fields and use an array for validations. I would like to also pass these values via AJAX: Although I haven't used a for loop in JavaScript before, it looks familiar. The current approach of the l ...

How can I perform a mongoose request using express post method?

I need help with querying my MongoDB database using a form in HTML and a post method, it's a bit complicated... Below is the HTML code : <!DOCTYPE html> <html> <head> <link rel="stylesheet" href="interface.css" /> ...

Tips for making objects rotate vertically on their axis and orbit around another object in three.js

Thank you in advance for all the support as I've been asking a lot of questions about my project. My project involves creating a simulation where a planet earth and moon rotate around a sun. (They're not exactly rotating around the sun, but more ...

How to generate a summary column in SAS using data from various columns

I am looking to generate a condensed single column in SAS that summarizes multiple columns for each individual within a data set. The data structure is as follows: Subject VisitNumber Exam Result Comments 001 1 Blood ...

Unable to transform this string into JSON format

I'm currently working on converting the given string into a JSONArray format. try { BufferedReader inputReader = new BufferedReader(new InputStreamReader( openFileInput(mFileName), "UTF-8")); String inputString; ...

Exploring ways in JavaScript to locate every occurrence of a string within segments of URLs embedded in HTML code

I have a large HTML file (~50MB) and I need to extract all instances of strings that are between two specific strings (which contain forward slashes) in URLs. var content = '<div><a href="https://sample.org/something/here/091209283/?para ...

An automatic slideshow with personalized navigation markers

<body> <div id="slide"> <div class="slideshow-container"> <div class="mySlides fade"> <img src="images/Image01.png"> </div> <div class="mySlides fade"> <img src="images/Image02.png"> < ...

Encountering problems while trying to upload JSON data to the database - receiving a "301 Moved Permanently

Currently working on a Symfony webservice and encountering an issue while making a POST call to the database. When using Postman for the POST request, I am receiving an error 301 - moved permanently. See below the controller code: /** * @Route("/post/inf ...

Challenges with moving images in Unslider

There seems to be an issue with the unslider-arrows on the unslider banner. The images are not sliding properly when transitioning to the next image without user input. Instead, they resize from small to full size starting at the top of the .banner div. ...

Prevent computed observables from being included in server data by using KnockoutJS

While working on this project, I came across a helpful section in that discusses "Determining if a property is a computed observable." In order to achieve this, I utilized the isComputed function to validate whether a property is indeed a computed observa ...

Regular expression that disallows names that end in anything other than letters, except for a dot

I've developed a regex pattern that validates whether a given text is a valid first or last name, returning either true or false: let letters = `a-zA-Z`; letters += `àáâäãåąčćęèéêëėįìíîïłńòóôöõøùúûüųūÿýżźñçč ...

Experiencing difficulties in retrieving property of a non-object when working with json and php

My current project involves using AngularJS to collect user input from a form, then sending this data to a PHP backend for processing. After decoding the JSON file in PHP, I then perform a database lookup to find information that matches the input values. ...

The .parents() method does not function properly when used with tables

I am attempting to display user details in a user list using AJAX JQuery, but it is not functioning as expected. It works for the first set of details within the same tr, but fails to work for the second detail in the td of the second row. How can I proper ...

Adjust the size of the external JavaScript code

Is it possible to adjust the size of the div element created by the external javascript code below? I've tried wrapping it in a div and setting the width, but the resizing doesn't seem to work. <div width = "100"><script type="text/jav ...

Display a loading indicator while Axios sends the Ajax request

I'm currently working on a Vue app and I am utilizing Axios for API calls. Before each call, I display a loading icon that hides once the call is completed. I'm curious if there is a way to implement this functionality globally so that I don&apo ...