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 API
  • isLoading – Boolean indicating if the initial fetch is in progress
  • refreshing – Boolean indicating if a pull-to-refresh is in progress
  • page – 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 the refreshing state.

  • onEndReached triggers pagination by incrementing the page state when the user scrolls to the end of the list. We use onEndReachedThreshold 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!

Similar Posts