1

I am trying to make a mock news react app and I am using newsapi's node package. This returns a response that has an array of objects inside one object. I set the state to the response of the newsapi function and when I log it to the console I get the object. I just can't display it on my site because I don't know how to display a state of objects inside a array.

Here is my App.js:

import React, { Component } from "react";
import Paper from "@material-ui/core/Paper";
import Divider from "@material-ui/core/Divider";
const NewsAPI = require("newsapi");
const newsapi = new NewsAPI("APIKEY");

class App extends Component {
  constructor() {
    super();
    this.state = { articles: {} };

    newsapi.v2
      .topHeadlines({
        category: "business",
        language: "en",
        country: "us"
      })
      .then(response => {
        this.setState({ articles: { response } });
        console.log(this.state.articles.response.articles[2]);
      });
  }

  render() {
    let article = this.state.articles;
    return (
      <div>
        <div style={{ display: "flex" }}>
          <div
            style={{ marginLeft: "23em", width: "75%", paddingBottom: "20px" }}
          >
            <Paper>
              <div style={{ textAlign: "center" }}>
                <p style={{ margin: "50px" }}>
                  <b />
                </p>
                <br />
              </div>
              <p>
                {article.map(articles => (
                  <p>{articles.name}</p>
                ))}
              </p>
              <br />
              <Divider />
            </Paper>
            <div style={{ textAlign: "center", paddingTop: "20px" }} />
          </div>
        </div>
      </div>
    );
  }
}

export default App;

I currently get the error that map isn't a function.

Response from API:

enter image description here

// Edited: Changed articles from array to object.

// Thanks to everyone... devserkan's answer helped the most and I can now move on with my project!

4
  • Can you share the API response? Commented Jul 29, 2018 at 18:45
  • Also, you are defining your articles state as an array but then in your setState you are setting it in an object. Commented Jul 29, 2018 at 18:46
  • Also added my response from the API. Commented Jul 29, 2018 at 18:51
  • You had it right the first time, keep articles as an array in your state. Commented Jul 29, 2018 at 18:57

3 Answers 3

1

First of all as told you should keep your articles state as an array in your state since it is an array in your response. Then you can map it easily. Here is a working example. I am faking API response here but you can use it for your situation.

class App extends React.Component {
  state = {
    articles: [],
  }

  response = {
    status: "ok",
    totalResults: 20,
    articles: [
      { author: "foo", title: "bar" },
      { author: "fizz", title: "buzz" },
    ]
  }

  getArticles = () =>
    new Promise( resolve =>
      setTimeout( () => resolve(this.response)), 500)

  componentDidMount() {
    this.getArticles()
      .then(response => this.setState({articles: response.articles}))
  }

  render() {
    const {articles} = this.state;
    return (
      <div>
        {
          articles.map( article => (
            <div>
            <p>Author: {article.author}</p>
            <p>Title: {article.title}</p>
            </div>
          ))
        }
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

For your situation, just look at my example and set your articles state as an empty array. Then use your newsApi call in your componentDidMount method. I'm providing your fixed code here but can't be sure it works since I can't test it.

class App extends Component {
  constructor() {
    super();
    this.state = { articles: [] };
  }

  getNews = () =>
    newsapi.v2
      .topHeadlines({
        category: "business",
        language: "en",
        country: "us"
      })
      .then(response => {
        this.setState({ articles: response.articles });
      });

  componentDidMount() {
    this.getNews();
  }

  render() {
    let articles = this.state.articles;
    return (
      <div>
        <div style={{ display: "flex" }}>
          <div
            style={{ marginLeft: "23em", width: "75%", paddingBottom: "20px" }}
          >
            <Paper>
              <div style={{ textAlign: "center" }}>
                <p style={{ margin: "50px" }}>
                  <b />
                </p>
                <br />
              </div>
              <p>
                {articles.map(article => (
                  <p>{article.author}</p>
                ))}
              </p>
              <br />
              <Divider />
            </Paper>
            <div style={{ textAlign: "center", paddingTop: "20px" }} />
          </div>
        </div>
      </div>
    );
  }
}

What have I changed?

  • Change articles shape in your state.
  • Create a function to get news: getNews.
  • In this function get the news and set the articles like this: this.setState({ articles: response.articles })
  • Add componentDidMount and invoke the created function.
  • In render method change article name to articles since this is more consistent. Also change articles to article in your map.
  • There is no name in an article, so I've changed it with author.
Sign up to request clarification or add additional context in comments.

7 Comments

How can I pass the response of the newsapi function into mount?
I've updated my answer. If you still get an error please add your code somewhere like codesandbox.io. So we can play with it.
Thank you... I have been learning MERN for about two weeks now and actually doing it yourself is very complex and confusing.
I can't compare to PHP or anything else since I don't know them if you mean those, but sure React is a great library not a language :)
I used to use the WAMP stack a lot but single page applications in either MEAN or MERN is the future I believe.
|
1

You are setting your articles as an object instead of an array. Then, when you try to "map" your articles, you get an error because object doesn't have a map function.

You can fix this by setting your articles object in your state to be an array:

this.setState({ articles: response.articles }); 

Note I removed curly braces around the response to prevent creating a new object

2 Comments

It is still saying map isn't a function.
And I want to print a list of titles. I can't figure out how to call an array and choose a value inside in object in the array.
-1

map work only for arrays, use for in or foreach

let articles_name = [];
for (var index in  this.state.articles) {articles_name.push(<p>this.state.articles[index].name</p>)}




   {article.map(articles => <p>{articles.name}</p>)}   can be replaced by  {articles_name} 

9 Comments

So how would I display my array of objects inside of the object?
i have editet, i had this problem in the past and i think i solved it so, this is one thing i hate on js compared to php
It is not so complex to do this as you said. Actually it is very easy. So, no need to hate anything.
@devserkan well this is one of stupid things on js, i can map and array but not an object(or array with keys) and this solution was more for other simlair problems(supply stuff over axios u will fight with this)
btw on J. Borga position i would do a console.log(article) and check if its really a array and not an object on level higher
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.