Building a High-Performance News App with React Native: A Step-by-Step Guide
Mobile apps have become an integral part of our daily lives, with users spending an average of 3 hours and 40 minutes per day in apps. News and information apps are particularly popular, as they keep us connected to the world around us.
Developing high-quality mobile apps can be challenging, but frameworks like React Native make it easier than ever to build performant, cross-platform apps with JavaScript.
What is React Native?
React Native is an open-source mobile application framework created by Facebook. It allows developers to use React along with native platform capabilities to build apps that look and feel native on both iOS and Android.
React Native offers several key benefits over other mobile app development approaches:
- Code Reuse – Write code once and deploy to both iOS and Android, saving time and resources.
- Performance – Compile to native code for optimal performance, with the ability to incorporate fully native components as needed.
- Developer Experience – Use JavaScript and the familiar React architecture, with support for tools like TypeScript and GraphQL.
Since launching in 2015, React Native has become incredibly popular. According to a 2020 StackOverflow survey, it‘s the 4th most loved framework, with 57.9% of surveyed developers expressing interest in continuing to develop with it.
High-profile apps built with React Native include Facebook, Instagram, Discord, Pinterest, Uber Eats, and Shopify. Over 500 contributors have committed code to the core React Native repository on GitHub.
In this guide, we‘ll harness the power of React Native to build a full-featured news reader app that pulls the latest articles from the web and displays them in an intuitive, responsive interface.
Setting up the Project
Before diving into the code, make sure your development environment is set up for React Native. You‘ll need Node.js and the React Native CLI installed. Follow the React Native docs to get started.
With the environment ready, create a new React Native project:
npx react-native init NewsApp
cd NewsApp
We‘ll be using a few additional libraries in this project:
- react-native-elements – A cross-platform UI toolkit with prebuilt components that match the look and feel of each platform
- axios – A popular JavaScript library for making HTTP requests
- moment – A lightweight library for parsing, validating, and displaying dates and times
Install them via npm:
npm install axios react-native-elements moment
We‘re now ready to start building our app!
Fetching News with the News API
To supply our app with news articles, we‘ll use the News API, a well-maintained API that aggregates headlines from over 70,000 sources around the web. It offers both free and paid plans, with the free tier providing plenty of functionality for our purposes.
Start by signing up for a free API key. Once you have a key, create a new file config.js
in the project root:
export default {
NEWS_API_KEY: ‘YOUR_API_KEY‘
};
Remember to replace ‘YOUR_API_KEY‘
with your actual API key from the News API dashboard.
Next, create a src
folder to organize our app code. Inside src
, create a services
folder with a file newsService.js
:
import axios from ‘axios‘;
import Config from ‘./../../config‘;
const URL = `https://newsapi.org/v2/top-headlines?country=us&apiKey=${Config.NEWS_API_KEY}`;
export async function getNews() {
try {
const response = await axios.get(URL);
return response.data.articles;
} catch (error) {
console.error(error);
return [];
}
}
This module exports a single async function getNews
that fetches the latest US news headlines from the News API using Axios. The function returns a promise that resolves to an array of article objects.
Note the error handling – if the API request fails for any reason, we log the error and return an empty array instead. This pattern, known as a "fallback value", prevents the app from crashing if the API is down or the network connection is lost.
With the news fetching logic set up, we can now focus on displaying the articles in our app.
Building the Article List
The core screen of our app will be a FlatList that renders an array of news articles fetched from the API. Create a new file screens/HomeScreen.js
:
import React, { useEffect, useState } from ‘react‘;
import { FlatList, SafeAreaView, StyleSheet } from ‘react-native‘;
import { getNews } from ‘../services/newsService‘;
import Article from ‘../components/Article‘;
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: ‘#fff‘,
},
});
export default function HomeScreen() {
const [isLoading, setLoading] = useState(true);
const [articles, setArticles] = useState([]);
const [refreshing, setRefreshing] = useState(false);
const [page, setPage] = useState(1);
useEffect(() => {
fetchNews();
}, [page]);
async function fetchNews() {
setLoading(true);
const result = await getNews(page);
setLoading(false);
setArticles([...articles, ...result]);
}
function handleRefresh() {
setPage(1);
setArticles([]);
setRefreshing(true);
fetchNews().then(() => setRefreshing(false));
}
function handleEndReached() {
if (!isLoading) {
setPage(page + 1);
}
}
return (
<SafeAreaView style={styles.container}>
{isLoading ? (
<ActivityIndicator />
) : (
<FlatList
data={articles}
renderItem={({ item }) => <Article article={item} />}
keyExtractor={item => item.url}
refreshControl={
<RefreshControl
colors={[‘#9Bd35A‘, ‘#689F38‘]}
refreshing={refreshing}
onRefresh={handleRefresh}
/>
}
onEndReached={handleEndReached}
onEndReachedThreshold={0.5}
/>
)}
</SafeAreaView>
);
}
This screen uses the useState
and useEffect
hooks to manage several pieces of local component state:
articles
– The array of article objects fetched from the News APIisLoading
– Boolean indicating if the initial fetch is in progressrefreshing
– Boolean indicating if a pull-to-refresh is in progresspage
– The current page of results being fetched from the API (for pagination)
When the component mounts, we fetch the first page of articles in a useEffect
hook. This triggers our loading state.
The fetchNews
async function calls our newsService
, updates the loading state, and appends the fetched articles to the articles
array. Note the spread syntax here – this ensures we don‘t overwrite existing articles when fetching subsequent pages.
The FlatList
component renders our Article
components (which we‘ll build next), with some additional configuration:
-
refreshControl
enables the pull-to-refresh functionality, tied to therefreshing
state. -
onEndReached
triggers pagination by incrementing thepage
state when the user scrolls to the end of the list. We useonEndReachedThreshold
to specify how close to the end the user must be before triggering the event. -
A
keyExtractor
function tells the list how to extract a unique key for each rendered item.
With this list component in place, the last step is to build out the actual Article
component that renders each individual article.
Creating the Article Component
Create a new folder components
in the src
directory, and add a file Article.js
:
import React from ‘react‘;
import { Linking, TouchableNativeFeedback, View } from ‘react-native‘;
import { Avatar, Card, Text } from ‘react-native-elements‘;
import moment from ‘moment‘;
const DEFAULT_IMAGE = ‘https://via.placeholder.com/150‘;
export default function Article({ article }) {
const {
title,
description,
url,
urlToImage,
publishedAt,
author,
source: { name },
} = article;
function handlePress() {
Linking.openURL(url);
}
return (
<TouchableNativeFeedback onPress={handlePress} useForeground>
<Card
featuredTitle={title}
featuredTitleStyle={styles.title}
image={{ uri: urlToImage || DEFAULT_IMAGE }}
>
<Text style={styles.description}>{description || ‘Read More‘}</Text>
<View style={styles.metadata}>
<Avatar rounded title={name[0]} containerStyle={styles.avatar} />
<Text style={styles.name}>{name}</Text>
<Text style={styles.timestamp}>
{moment(publishedAt).format(‘MMM Do, h:mm a‘)}
</Text>
{author && <Text style={styles.author}>By {author}</Text>}
</View>
</Card>
</TouchableNativeFeedback>
);
}
const styles = {
// Styles omitted for brevity
};
This component renders a pressable Card from react-native-elements that displays several properties of the provided article
prop: the title, description, image, source name, author, and formatted publish timestamp using Moment.js.
Note how we defensively access properties like urlToImage
and author
– not all articles returned by the News API will have these properties. By using default values and short-circuit evaluation, we can avoid null pointer exceptions.
On Android, we wrap the Card
with a TouchableNativeFeedback
to create a native press animation. When pressed, the handlePress
method will open the article URL in the device browser using the React Native Linking
API.
Wrapping Up
With our core components built, the final step is adding the HomeScreen
to our app‘s navigation flow. React Native includes the react-navigation
library for declarative routing and navigation.
Install the necessary navigation dependencies:
npm install @react-navigation/native @react-navigation/stack
Then update App.js
to set up the main app stack navigator:
import ‘react-native-gesture-handler‘;
import React from ‘react‘;
import { NavigationContainer } from ‘@react-navigation/native‘;
import { createStackNavigator } from ‘@react-navigation/stack‘;
import HomeScreen from ‘./src/screens/HomeScreen‘;
const Stack = createStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ title: ‘Top Headlines‘ }}
/>
</Stack.Navigator>
</NavigationContainer>
);
}
The app is now complete! Let‘s test it out.
Running the App
To launch the app on iOS:
npx react-native run-ios
For Android:
npx react-native run-android
If all goes well, you should see your new app launch in the simulator, pulling the latest news articles from the web. Try refreshing the list, scrolling to the end to trigger pagination, and tapping into articles to open them in the browser.
Conclusion
Congratulations! You now have a functional, responsive news reader app built entirely with React Native and JavaScript.
While this tutorial covered the core steps of building the app, there are plenty of additional optimizations and features you could add:
-
Performance Enhancements – Profile the app with tools like Flipper to identify and fix performance bottlenecks. Reduce the initial bundle size by lazily loading non-critical dependencies.
-
Offline Support – Use a library like Redux Persist to cache fetched articles in local storage, allowing users to access content offline or on slow network connections.
-
UI Polish – Enhance the user experience with skeleton loading placeholders, empty states, and smooth transitions between screens.
-
Code Quality – Incorporate static type checking with TypeScript, unit tests with Jest, and enforce consistent formatting with Prettier.
-
CI/CD Pipeline – Automate the testing and deployment process using a service like GitHub Actions or CircleCI.
By leveraging the power and flexibility of React Native, we were able to build a professional, cross-platform app in a fraction of the time it would take to build separate native apps for iOS and Android.
I encourage you to continue exploring React Native and its extensive ecosystem. With a strong grasp of JavaScript and React fundamentals, you‘ll be well-equipped to tackle even the most ambitious mobile app projects.
The full source code for the news app is available on GitHub. Feel free to fork the repository and experiment with adding new features or customizing the design.
If you have any questions or feedback, don‘t hesitate to reach out! I‘m always happy to help fellow developers however I can.
Happy coding!