Requirements for building the app:
- A basic understanding of the JavaScript language.
- Node.js, and react native.
- Libraries used: moment, react-native, react-native-elements.
If you’re not familiar with these resources, don’t worry — they are quite easy to use.
The topics we will cover in the post are:
- News API
- Fetch API
- FlatList
- Pull down to refresh
- Linking
And more…so let’s get started!
You can find the full project repo HERE.
News API
A simple and easy-to-use API that returns JSON metadata for headlines and articles live all over the web right now. — NewsAPI.org
First, you should go ahead and sign up for News Api to get your free apiKey (your authentication key).
Create a new React Native project, and call it news_app
(or whatever you want). In the project directory, make a new folder and call it src
. In src
create a folder an name it components
. So your project directory should look something like this:
In the src folder, create a new file called news.js . In this file we are going to fetch the JSON that contains the headlines from the News API.
news.js
const url =
"https://newsapi.org/v2/top-headlines?country=us&apiKey=YOUR_API_KEY_HERE";
export async function getNews() {
let result = await fetch(url).then(response => response.json());
return result.articles;
}
Make sure you replace YOUR_API_KEY_HERE
with your own API key. For more information about the News API, go to newsapi docs.
Now we declare the getNews
function, which is going to fetch the articles for us. Export the function so we can use it in our App.js
file.
App.js
import React from 'react';
import { FlatList } from 'react-native';
// Import getNews function from news.js
import { getNews } from './src/news';
// We'll get to this one later
import Article from './src/components/Article';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = { articles: [], refreshing: true };
this.fetchNews = this.fetchNews.bind(this);
}
// Called after a component is mounted
componentDidMount() {
this.fetchNews();
}
fetchNews() {
getNews()
.then(articles => this.setState({ articles, refreshing: false }))
.catch(() => this.setState({ refreshing: false }));
}
handleRefresh() {
this.setState(
{
refreshing: true
},
() => this.fetchNews()
);
}
render() {
return (
<FlatList
data={this.state.articles}
renderItem={({ item }) => <Article article={item} />}
keyExtractor={item => item.url}
refreshing={this.state.refreshing}
onRefresh={this.handleRefresh.bind(this)}
/>
);
}
}
In the constructor, we define the initial state. articles
will store our articles after we fetch them, and refreshing
will help us in refresh animation. Notice that I setrefreshing
to true
, because when we start the app, we want the animation to start while we load the articles.
componentDidMount
is invoked immediately after a component is mounted. Inside it we call the fetchNews
method.
componentDidMount() {
this.fetchNews();
}
In fetchNews
we call getNews()
which returns a promise. So we use the .then()
method which takes a callback function, and the callback function takes an argument (the articles).
Now assign the articles in the state to the articles argument. I only typed articles
because it’s a new ES6 syntax that means { articles: articles } , and we set refreshing
to false
to stop the spinner animation.
fetchNews() {
getNews().then(
articles => this.setState({ articles, refreshing: false })
).catch(() => this.setState({ refreshing: false }));
}
.catch()
is called in rejected cases.
handleRefresh
starts the spinner animation and call fetchNews()
. We pass () => this.fetchNews()
, so it’s called immediately after we assign the state.
handleRefresh() {
this.setState({ refreshing: true },() => this.fetchNews());
}
In the render
method, we return a FlatList
element. Then we pass some props. data
is the array of articles from this.state
. The renderItem
takes a function to render each item in the array, but in our case it just returns the Article
component we imported earlier (we’ll get there). And we pass the article
item as a prop to use later in that component.
Article.js
In src/components
create a new JavaScript file and call it Article.js
.
Let’s start by installing two simple libraries using npm: react-native-elements
, which gives us some premade components we could use, and moment
that will handle our time.
run using terminal/cmd:
npm install --save react-native-elements moment
In Article.js:
import React from 'react';
import { View, Linking, TouchableNativeFeedback } from 'react-native';
import { Text, Button, Card, Divider } from 'react-native-elements';
import moment from 'moment';
export default class Article extends React.Component {
render() {
const {
title,
description,
publishedAt,
source,
urlToImage,
url
} = this.props.article;
const { noteStyle, featuredTitleStyle } = styles;
const time = moment(publishedAt || moment.now()).fromNow();
const defaultImg =
'https://wallpaper.wiki/wp-content/uploads/2017/04/wallpaper.wiki-Images-HD-Diamond-Pattern-PIC-WPB009691.jpg';
return (
<TouchableNativeFeedback
useForeground
onPress={() => Linking.openURL(url)}
>
<Card
featuredTitle={title}
featuredTitleStyle={featuredTitleStyle}
image={{
uri: urlToImage || defaultImg
}}
>
<Text style={{ marginBottom: 10 }}>
{description || 'Read More..'}
</Text>
<Divider style={{ backgroundColor: '#dfe6e9' }} />
<View
style={{ flexDirection: 'row', justifyContent: 'space-between' }}
>
<Text style={noteStyle}>{source.name.toUpperCase()}</Text>
<Text style={noteStyle}>{time}</Text>
</View>
</Card>
</TouchableNativeFeedback>
);
}
}
const styles = {
noteStyle: {
margin: 5,
fontStyle: 'italic',
color: '#b2bec3',
fontSize: 10
},
featuredTitleStyle: {
marginHorizontal: 5,
textShadowColor: '#00000f',
textShadowOffset: { width: 3, height: 3 },
textShadowRadius: 3
}
};
There is a lot going on here. First, we start by destructuring the article
prop and the styles
object defined below the class.
In render
we define time
to store the time for when the article was published. We use the moment
library to convert the date to the time passed since then, and we pass publishedAt
or time from now if publishedAt
is null
.
defaultImg
is assigned an image URL in case the URL of the article image is null
.
The render
method returns TouchableNativeFeedback
(use TouchableOpacity
instead if it does not work on your platform) to handle when the user presses the card. We pass it some props: useForground
which tells the element to use the foreground when displaying the ripple effect on the card, and onPress
, which takes a function and executes it when the user presses the card. We passed () => Linking.openUrl(url)
which simply opens the URL to the full article when we press the card.
The card takes three props: featuredTitle
which is just a fancy title placed over the image you could use title
instead if you want, featuredTitleStyle
to style it, and image which is the article image from the article prop. Otherwise, if its null
, it’s going to be the defaultImg
.
..
featuredTitle={title}
featuredTitleStyle={featuredTitleStyle}
image={{ uri: urlToImage || defaultImg }}
..
As for the text
element, it will hold the description for the article.
<Text style={{ marginBottom: 10 }}>{description}</Text>
We added a divider
to separate the description from time and source name.
<Divider style={{ backgroundColor: '#dfe6e9' }} />
Below the Divider
, we have a View
that contains the source name and the time the article was published.
..
<View
style={{ flexDirection: ‘row’, justifyContent: ‘space-between’ }} >
<Text style={noteStyle}>{source.name.toUpperCase()}</Text>
<Text style={noteStyle}>{time}</Text>
</View>
..
After the class
, we defined the styles for these components.
Now if we run the app:
and we can refresh the app
There you go! The source code for the app is available on GitHub HERE you can improve upon it and make a pull request😄.
I hope you enjoyed my article! If you have any questions at all, feel free to comment or reach me on twitter and I will definitely help :)
Also don't forget to share the article😄👇.
Top comments (21)
Great post! I might have to go play with this news API sometime.
One possible improvement in code clarity: in your
getNews
function, should thisbe replaced with this?
Since you're just passing it along to the next
then
call, it seems redundant to me and could be removed to make the code a little more clear. If you do have a reason for doing it that way, I'd love to hear why!thanks, i might've forgot that i added the await keyword.
I'm stuck at the
fetch
section... It keeps giving meNetwork request failed
error, however I can manage to request using the same code in chrome console or using other api, any idea?what is your device?
Thanks for reply, I was developing with Genymotion, I tried a real device after you brought it up and it worked.. that's weird, thanks anyway :)
Hello,
I have found similar article related to react native, hope this will be helpful to create first reactapp : skptricks.com/2018/06/how-to-creat...
What are you use of theme for syntax in your Code EDITOR
Sorry for the late reply, I use Relaxed color theme, indent-rainbow and Rainbow Brackets plugins for VS Code:)
What are you use of theme for this syntax in your Code Editor?
thepracticaldev.s3.amazonaws.com/i...
Thank You Mohammed.. I will give it a try 👏🏽👏🏽
Sure thing, thanks for reading👍
Hello All, I have implemented CardView for react-native with elevation, that support android(All version) and iOS. github.com/Kishanjvaghela/react-na.... Check this out
Thx Mohammed, nice post!
happy you liked it:)
Hey Mohammed, you might want to hide your api key?
Thanks, i fixed the issue:)
Can I search for specific articles in the api
Some comments may only be visible to logged-in visitors. Sign in to view all comments.