1

I have this json object which I have taken from the news API and want to print out the author of just one of the articles. I wanted to know how to do it within a react component which I have called 'author'.

Here is the json object: it's too long to include here but have the link for you to see.

It's accessible from https://newsapi.org/ and has a total of 20 articles.

I have this react component which I am trying to then print one of the article's authors:

import React, { Component } from 'react';

const APIurl = 'https://newsapi.org/v2/top-headlines? 
country=it&apiKey=0b3e87958d0b4e71a9e2ed3eea69237a';

class Author extends Component {
    constructor(props) {
        super(props);
        this.state = {};
    }

    componentDidMount() {
        fetch(APIurl)
            .then(response => response.json())
            .then(response => {
                this.setState({
                    articles: response
                })
            })
    }

    render() {
        return (
            <h5 class="f6 ttu tracked black-80">
                {this.state.articles.article[0].author}
            </h5>
       );
   }
}

export default Author;

However, something must not be quite right because I get this error:

TypeError: Cannot read property 'articles' of undefined

 21 | render() {
 22 |   return (
 23 |       <h5 class="f6 ttu tracked black-80">
> 24 |          {this.state.articles.articles[0].author}
 25 |       </h5>
 26 |   );
 27 | }

I'm not sure what I have done wrong. Also sorry for the poor formating of the json object.

I've now made some changes after seeing what has been suggested below so that my code looks like this:

import React, { Component } from 'react';

const APIurl = 'https://newsapi.org/v2/top-headlines?       country=it&apiKey=0b3e87958d0b4e71a9e2ed3eea69237a';

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

    componentDidMount() {
        fetch(APIurl)
            .then(response => response.json())
            .then(response => {
                this.setState({
                    articles: response
                })
            })
    }

    render() {
        const { articles } = this.state;
        return (
            <h5 class="f6 ttu tracked black-80">
                {articles.length>0 && articles.articles[1].author}
            </h5>
        );
    }
}

export default Author;

However, it still doesn't print out anything in the author react component even though when I go to the chrome developer tools and see the state of the component it looks like this:

State
    articles: {…}
        articles: Array[20]
            0: {…}
            1: {…}
                 author: "Davide Stoppini"
                 description: "A Pisa, divertente pareggio con i russi, più avanti per quanto riguarda la condizione fisica. Passi in avanti rispetto al Sion: bene gli esterni offensivi, anche i due attaccanti confermano la confide…"
                 publishedAt: "2018-07-21T20:20:21Z"
                 source: {…}
                 title: "Inter, fuochi d'artificio con lo Zenit: è 3-3. In gol Icardi e Lautaro"
                 url: "https://www.gazzetta.it/Calcio/Serie-A/Inter/21-07-2018/inter-fuochi-d-artificio-lo-zenit-3-3-gol-icardi-lautaro-280799153444.shtml"
                  urlToImage:"https://images2.gazzettaobjects.it/methode_image/2018/07/21/Calcio/Foto%20Calcio%20-%20Trattate/1d50f03c94d965c2ca84bd3eec0137c9_169_xl.jpg

*Note: this is only showing the first second element of the articles array.

3 Answers 3

1

Basically, you have to declare articles as empty array initially as follows:

this.state = {
   articles: []
};

And also need to modify your code inside render as follows:

{this.state.articles && (this.state.articles.article.length>0) &&
this.state.articles.article[0].author
}

Hope it will help you.

Sign up to request clarification or add additional context in comments.

Comments

0

The problem you are having is because your code is not prepared to go through the lifecycle of React. Before you get the data in the componentDidMount phase there is a render phase, that is where the error is happening. In that render phase articles should be an empty array without data and then you need a check to avoid rendering any stuff if the array is empty. So to avoid to have that error in the render phase before the componentDidMount phase you need to set in state an empty array called articles, and in the render method to check if it is not empty, to render the value you want.

import React, { Component } from 'react';

const APIurl = 'https://newsapi.org/v2/top-headlines? 
country=it&apiKey=0b3e87958d0b4e71a9e2ed3eea69237a';

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

    componentDidMount() {
        fetch(APIurl)
            .then(response => response.json())
            .then(response => {
                this.setState({
                    articles: response.articles
                })
            })
    }

    render() {
      const { articles } = this.state;
        return (
            <h5 class="f6 ttu tracked black-80">
                {articles.length > 0 && articles[0].author}
            </h5>
       );
   }
}

export default Author;

2 Comments

Thanks for the advice. I've made some changes to my code to do what you suggested but it still doesn't print anything out in the author react component. I've added some more information in my post just in case that helps.
You missed the part in the response of the fetch where I only left to be saved the articles attribute of the response object as this.state.articles. If you still have doubts on how to access to the data you save in the state, set a console.log(articles) after the state destructuring in the render method (const { articles } = this.state;) and you will see how you must access the data.
0

News App in React Native:

const SITE_URL =
  "https://newsapi.org/v2/top-headlines?country=us&category=business&apiKey=a39bbc7131c649a3ad23fe79063d996f";

const TestScreen = () => {
 

  const [myData, setMyData] = useState();
  useEffect(() => {
    axios
      .get(SITE_URL)
      .then((res) => {
        // console.log("Response from main API: ", res);
        console.log(
          "-----------------------------------------------------------  Start"
        );

        // console.log("Response from Home Data Data: ", res.data.data);
        console.log(
          "Response from NEWS data articles: ",
          res.data.articles
        );
        console.log(
          "-----------------------------------------------------------  End"
        );
        // let companyData = res.data.data;
        let companyData = res.data.articles;
        setMyData(companyData);

        setData({
          Company: companyData,
          Description: "",
        });
      })
      .catch((err) => {
        console.log(err);
      });
  }, []);
  //   console.log("myData:", { myData });
  const renderItem = ({ item, index }) => (
    <TouchableOpacity style={styles.container}>
      <Text style={styles.title}>
        {index}. {item.author}
      </Text>
      <Text> {item.description} </Text>
      <View>
        <Image
          style={{
            width: 500,
            height: 100,
          }}
          source={{
            uri: item.urlToImage,
          }}
        />
      </View>
    </TouchableOpacity>
  );

  return (
    <View style={styles.container}>
      <Text>Read Later Screen</Text>
      <Text>|</Text>
      {<FlatList data={myData} renderItem={renderItem} />}
    </View>
  );
};
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center",
  },
});

export default TestScreen;

Comments

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.