Open In App

Create a News Reader app using React-Native

Last Updated : 14 Dec, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Creating the News Reader application using React-Native language is an exciting project. Using this project, the users can read the news in the application itself, by filtering them according to the categories as per their interest. In this article, we will develop the complete News Reader application to fetch real-time news from News API.

Preview of final output: Let us have a look at how the final application will look like.

image_123986672

Prerequisites:

Approach to create News Reader App:

  • This application is a single-page application.
  • We have used the Axios to make the asynchronous HTTP requests to the News API. Using this, the news is fetched based on the user’s selected category, which also updates the app’s state.
  • When the user clicks on the news, the Modal is shown with the details of the news, The user can click on the link to visit the source of the news to get more insights from it.
  • User can filter the news as per their interest by selecting the interest category from Picker.

Steps to Create React Native Application:

Step 1: Create the project:

npx create-expo-app news-app

Step 2: Navigate to the project

cd news-app

Step 3: Install the packages as follows:

npx expo install react-native-elements react-native-picker-select axios

Project Structure:

PS

The updated dependencies in package.json file will look like:

"dependencies": {
"axios": "^1.6.2",
"expo": "~49.0.15",
"expo-status-bar": "~1.6.0",
"react": "18.2.0",
"react-native": "0.72.6",
"react-native-elements": "^3.4.3",
"react-native-picker-select": "^9.0.0"
}

Example: In this example, we are following the above-explained approach.

Javascript




// App.js
import React, { useState, useEffect } from 'react';
import {
    View, Text, FlatList, Modal, TouchableOpacity,
    RefreshControl, ActivityIndicator, Linking
} from 'react-native';
import { Card, Icon, Overlay } from 'react-native-elements';
import RNPickerSelect from 'react-native-picker-select';
import { styles as appStyles, pickerSelectStyles } from './styles';
 
const App = () => {
    const [news, setNews] = useState([]);
    const [selectedNews, setSelectedNews] = useState(null);
    const [modalVisible, setModalVisible] = useState(false);
    const [selectedCategory, setSelectedCategory] =
        useState('general');
    const [refreshing, setRefreshing] = useState(false);
    const [loading, setLoading] = useState(true);
 
    useEffect(() => {
        fetchNews();
    }, [selectedCategory]);
 
    const fetchNews = async () => {
        try {
            setLoading(true);
            const response = await fetch(
`https://newsapi.org/v2/top-headlines?country=us&category=${selectedCategory}&apiKey=bd3916e8bfe04202b97dc9ad162b8483`
            );
            const result = await response.json();
            setNews(
                result.articles
                    .map(
                        article =>
                        (
                            {
                                ...article,
                                category: selectedCategory
                            }
                        )));
        } catch (error) {
            console.error('Error fetching news:', error.message);
        } finally {
            setLoading(false);
        }
    };
 
    const onRefresh = async () => {
        setRefreshing(true);
        try {
            await fetchNews();
        } finally {
            setRefreshing(false);
        }
    };
 
    const openNewsLink = () => {
        if (selectedNews?.url) {
            Linking.openURL(selectedNews.url);
        }
    };
 
    const renderItem = ({ item }) => (
        <Card containerStyle={appStyles.cardContainer}>
            <Card.Title
                style={appStyles.cardTitle}>
                {item.title}
            </Card.Title>
            <Card.Image
                source={{ uri: item.urlToImage }}
                style={appStyles.cardImage} />
            <Text
                style={appStyles.description}>
                {item.description}
            </Text>
            <View style={appStyles.cardFooter}>
                <View style={appStyles.categoryContainer}>
                    <Icon name="tag"
                        type="font-awesome"
                        color="gray" size={16} />
                    <Text style={appStyles.categoryLabel}>
                        {item.category}
                    </Text>
                </View>
                <TouchableOpacity
                    style={appStyles.readMoreButton}
                    onPress={() => {
                        setSelectedNews(item);
                        setModalVisible(true);
                    }}
                >
                    <Text style={appStyles.readMoreButtonText}>
                        Read more
                    </Text>
                </TouchableOpacity>
            </View>
        </Card>
    );
 
    return (
        <View style={appStyles.container}>
            <View style={appStyles.headerContainer}>
                <Icon name="newspaper-o"
                    type="font-awesome"
                    color="green" size={30} />
                <Text style={appStyles.header}>
                    GeeksforGeeks News Reader
                </Text>
            </View>
            <View style={appStyles.categoryPickerContainer}>
                <Text style={appStyles.categoryPickerLabel}>
                    Select Category:
                </Text>
                <RNPickerSelect
                    placeholder={{}}
                    onValueChange={
                        (itemValue) =>
                            setSelectedCategory(itemValue)
                    }
                    items={[
                        { label: 'General', value: 'general' },
                        { label: 'Business', value: 'business' },
                        { label: 'Technology', value: 'technology' },
                        { label: 'Sports', value: 'sports' },
                    ]}
                    style={pickerSelectStyles}
                />
            </View>
 
            {loading ? (
                <ActivityIndicator size="large"
                    color="#3498db"
                    style={{ marginTop: 20 }} />
            ) : (
                <FlatList
                    data={news}
                    renderItem={renderItem}
                    keyExtractor={(item) => item.url}
                    refreshControl={
                        <RefreshControl
                            refreshing={refreshing}
                            onRefresh={onRefresh} />
                    }
                />
            )}
 
            <Modal animationType="slide"
                transparent={false} visible={modalVisible}>
                <Overlay isVisible={modalVisible}
                    overlayStyle={appStyles.modalContainer}
                    onBackdropPress={
                        () => setModalVisible(false)
                    }>
                    <Card containerStyle={appStyles.modalCard}>
                        <Card.Title style={appStyles.cardTitle}>
                            {selectedNews?.title}
                        </Card.Title>
                        <Card.Image source={{ uri: selectedNews?.urlToImage }}
                            style={appStyles.cardImage} />
                        <Text>{selectedNews?.content}</Text>
                        <TouchableOpacity style={appStyles.readMoreButton}
                            onPress={openNewsLink}>
                            <Text style={appStyles.readMoreButtonText}>
                                Read Full Article
                            </Text>
                        </TouchableOpacity>
                    </Card>
                </Overlay>
            </Modal>
        </View>
    );
};
 
export default App;


Javascript




//styles.js
import { StyleSheet } from 'react-native';
const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#ecf0f1',
        padding: 10,
    },
    headerContainer: {
        flexDirection: 'row',
        alignItems: 'center',
        marginBottom: 10,
        paddingTop: 50,
    },
    header: {
        fontSize: 24,
        fontWeight: 'bold',
        marginLeft: 10,
    },
    categoryPickerContainer: {
        flexDirection: 'row',
        alignItems: 'center',
        marginBottom: 10,
    },
    categoryPickerLabel: {
        fontSize: 16,
        marginRight: 10,
    },
    cardContainer: {
        borderRadius: 10,
        marginBottom: 15,
        overflow: 'hidden',
    },
    cardTitle: {
        fontSize: 18,
        fontWeight: 'bold',
    },
    cardImage: {
        height: 200,
        resizeMode: 'cover',
        borderRadius: 10,
    },
    categories: {
        flexDirection: 'row',
        justifyContent: 'space-around',
        marginBottom: 10,
        flexWrap: 'wrap',
    },
    categoryContainer: {
        flexDirection: 'row',
        alignItems: 'center',
    },
    categoryLabel: {
        color: 'gray',
        marginLeft: 5,
    },
    description: {
        marginVertical: 10,
    },
    cardFooter: {
        flexDirection: 'row',
        justifyContent: 'space-between',
        marginTop: 10,
        alignItems: 'center',
    },
    readMoreButton: {
        backgroundColor: '#3498db',
        padding: 8,
        borderRadius: 5,
        marginTop: 10,
        alignItems: 'center',
    },
    readMoreButtonText: {
        color: 'white',
        fontWeight: 'bold',
    },
    modalContainer: {
        padding: 20,
    },
    modalCard: {
        borderRadius: 10,
        overflow: 'hidden',
    },
});
const pickerSelectStyles = StyleSheet.create({
    inputIOS: {
        fontSize: 16,
        paddingVertical: 12,
        paddingHorizontal: 10,
        borderWidth: 1,
        borderColor: 'gray',
        borderRadius: 5,
        color: 'black',
        paddingRight: 30,
    },
    inputAndroid: {
        fontSize: 16,
        paddingHorizontal: 10,
        paddingVertical: 8,
        borderWidth: 0.5,
        borderColor: 'purple',
        borderRadius: 8,
        color: 'black',
        paddingRight: 30,
    },
});
export { styles, pickerSelectStyles };


Step to Run the Application:

Step 1: Navigate to the terminal or command prompt and type the required command there to run the React native application.

npx expo start

Step 2: Depending on your Operating System, type the following command in terminal

  • To run on Android:
npx react-native run-android
  • To run on IOS:
npx react-native run-ios

Output:

Output



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads