Ryan Travers
Ryan Travers

Reputation: 33

Extracting data from json object from API with JavaScript React Native

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.

Upvotes: 1

Views: 6969

Answers (3)

questerstudios
questerstudios

Reputation: 189

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;

Upvotes: 0

Sandy.....
Sandy.....

Reputation: 2870

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.

Upvotes: 1

Dez
Dez

Reputation: 5838

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;

Upvotes: 0

Related Questions