Reputation: 1865
I was trying to implement a News App. It should show a list of news headlines on start with thumbnail image and description and then on clickinh the url should be opened in browser. But, i am stuck on halfway getting a Type Error.
Here are the codes of my NewsList and NewsDetail files.
NewsList.js
import React, { Component } from 'react';
import { ScrollView } from 'react-native';
import axios from 'axios';
import NewsDetail from './NewsDetail';
class NewsList extends Component {
constructor(props) {
super(props);
this.state = {
news: []
};
}
//state = {news: []};
componentWillMount() {
axios.get('https://newsapi.org/v2/top-headlines?country=in&apiKey=MYAPIKEY')
.then(response => this.setState({news: response.data }));
}
renderNews() {
return this.state.news.map(newsData =>
<NewsDetail key={newsData.title} newsData={newsData} />
);
}
render() {
console.log("something",this.state);
return (
<ScrollView>
{this.renderNews()}
</ScrollView>
);
}
}
export default NewsList;
NewsDetail.js
import React from 'react';
import { Text, View, Image, Linking } from 'react-native';
import Card from './Card';
import CardSection from './CardSection';
import Button from './Button';
import NewsList from './NewsList';
const NewsDetail =({ newsData }) => {
const { title, description, thumbnail_image, urlToImage, url } = newsData;
const { thumbnailStyle,
headerContentStyle,
thumbnailContainerStyle,
headerTextStyle,
imageStyle } =styles;
return(
<Card>
<CardSection>
<View>
<Image
style={thumbnailStyle}
source={{uri: urlToImage}}
/>
</View>
<View style={headerContentStyle}>
<Text style={headerTextStyle}>{title}</Text>
<Text>{description}</Text>
</View>
</CardSection>
<CardSection>
<Image
style={imageStyle}
source={{uri:urlToImage}}
/>
</CardSection>
<CardSection>
<Button onPress={() =>Linking.openURL(url)} >
ReadMore
</Button>
</CardSection>
</Card>
);
};
export default NewsDetail;
StackTrace of the Error i am getting
TypeError: this.state.news.map is not a function
This error is located at: in NewsList (at App.js:11) in RCTView (at View.js:78) in View (at App.js:9) in App (at renderApplication.js:35) in RCTView (at View.js:78) in View (at AppContainer.js:102) in RCTView (at View.js:78) in View (at AppContainer.js:122) in AppContainer (at renderApplication.js:34) NewsList.renderNews NewsList.js:21:31 NewsList.proxiedMethod createPrototypeProxy.js:44:29 NewsList.render NewsList.js:31:18 NewsList.proxiedMethod createPrototypeProxy.js:44:29 finishClassComponent ReactNativeRenderer-dev.js:8707:30 updateClassComponent ReactNativeRenderer-dev.js:8674:11 beginWork ReactNativeRenderer-dev.js:9375:15 performUnitOfWork ReactNativeRenderer-dev.js:11771:15 workLoop ReactNativeRenderer-dev.js:11839:25 Object.invokeGuardedCallback ReactNativeRenderer-dev.js:39:9
App.js
import React from 'react';
import { AppRegistry, View } from 'react-native';
import Header from './header';
import NewsList from './NewsList';
//create component
const App = () => {
return(
<View style={{ flex:0 }}>
<Header headerText={'Headlines'} />
<NewsList />
</View>);
}
export default App;
AppRegistry.registerComponent('news', () => App);
Upvotes: 0
Views: 427
Reputation: 191749
You can actually go to https://newsapi.org/v2/top-headlines?country=in&apiKey="MY_API_KEY" in the browser or use a tool like curl
or Postman to check what the response is. The data response is an object, but you need an array. articles
is most likely the property you are after.
You may also want to check that this is an array and update what is displayed appropriately.
.then(response => {
const news = response.data.articles;
if (Array.isArray(news)) {
this.setState({ news });
} else {
this.setState({ errorMessage: 'Could not load any articles' });
}
});
Upvotes: 1
Reputation: 3105
The error you're getting - TypeError: this.state.news.map is not a function
, means that news is not an array.
By checking your api response you should do:
this.setState({news: response.data.articles })
.
Upvotes: 2