Open In App

Create a Blog App using React-Native

Last Updated : 18 May, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

This article will help you make a simple blog app using React Native. The app lets users add, edit, and delete blog posts, making it easy to manage content. You will learn how to use different React Native features to create a user-friendly design that checks if the input is correct, making sure all posts have a title and some content.

To give you a better idea of what we’re going to create, let’s watch a demo video.

Demo Video

Prerequisites

Approach

In this code, we are making a simple React Native app for a blog. It lets users look at a list of blog posts, choose a post to read, and add new posts to the list. Users can also edit or delete existing posts. The code checks to make sure that new posts have both a title and content and are not empty. It uses different React Native components like View, Text, TextInput, Button, and FlatList to show the blog posts and handle user actions. The styling is done carefully using StyleSheet for a neat appearance.

Step-by-Step Implementation

Step 1: Create a React Native Project

Now, create a project with the following command.

npx create-expo-app app-name --template

Note: Replace the app-name with your app name for example : react-native-demo-app

Next, you might be asked to choose a template. Select one based on your preference as shown in the image below. I am selecting the blank template because it will generate a minimal app that is as clean as an empty canvas in JavaScript.

It completes the project creation and displays a message: "Your Project is ready!" as shown in the image below.

Now go into your project folder, i.e., react-native-demo

cd app-name

Project Structure

Step 2: Run  Application

Start the server by using the following command.

npx expo start

Then, the application will display a QR code.

  • For the Android users,
    • For the Android Emulator, press "a" as mentioned in the image below.
    • For the Physical Device, download the "Expo Go" app from the Play Store. Open the app, and you will see a button labeled "Scan QR Code." Click that button and scan the QR code; it will automatically build the Android app on your device.
  • For iOS users, simply scan the QR code using the Camera app.
  • If you're using a web browser, it will provide a local host link that you can use as mentioned in the image below.

Step 3: Start Coding

- Import libraries: Import required libraries at the top of the file.

JavaScript
// Import the useState hook from React for managing state in functional components
import { useState } from 'react';
// Import core React Native components for building the UI
import {
    View,           // Container component for layout
    Button,         // Button component for user actions
    TextInput,      // Input field for text entry
    Text,           // Component for displaying text
    FlatList,       // Efficient list view for rendering posts
    StyleSheet,     // Utility for creating component styles
    TouchableOpacity // Wrapper for making views touchable
} from 'react-native';


- StyleSheet: Create a StyleSheet to style components like container, headingContainer, heading, etc.

JavaScript
// Define styles for the components using StyleSheet.create
const styles = StyleSheet.create({
    // Main container style for the app
    container: {
        flex: 1, // Take up the full screen
        paddingTop: 40, // Space from the top
        paddingHorizontal: 20, // Space on left and right
    },
    // Container for the heading section
    headingContainer: {
        backgroundColor: '#3498db', // Blue background
        padding: 10, // Padding inside the container
        borderRadius: 10, // Rounded corners
        marginBottom: 20, // Space below the heading
    },
    // Style for the main heading text
    heading: {
        fontSize: 24, // Large font size
        fontWeight: 'bold', // Bold text
        textAlign: 'center', // Centered text
        color: 'white', // White text color
    },
    // Container for each blog post
    postContainer: {
        borderWidth: 1, // Border thickness
        borderColor: '#ccc', // Light gray border color
        padding: 20, // Padding inside the post
        marginBottom: 20, // Space below each post
        borderRadius: 10, // Rounded corners
    },
    // Style for the post title
    postTitle: {
        fontSize: 18, // Medium-large font size
        fontWeight: 'bold', // Bold text
        marginBottom: 10, // Space below the title
    },
    // Style for the post content text
    postContent: {
        fontSize: 14, // Normal font size
        textAlign: 'left', // Left-aligned text
    },
    // Style for the delete/edit button container
    deleteButton: {
        alignSelf: 'flex-end', // Align to the right
        marginTop: 10, // Space above the button
    },
    // Style for the edit button text
    editButtonText: {
        color: 'green', // Green text color
    },
    // Style for the delete button text
    deleteButtonText: {
        color: 'red', // Red text color
    },
    // Container for the selected post view
    selectedPostContainer: {
        padding: 20, // Padding inside the container
        marginBottom: 20, // Space below the container
        borderWidth: 1, // Border thickness
        borderColor: '#ccc', // Light gray border color
        borderRadius: 10, // Rounded corners
    },
    // Style for the selected post's title
    selectedPostTitle: {
        fontSize: 24, // Large font size
        fontWeight: 'bold', // Bold text
        marginBottom: 10, // Space below the title
    },
    // Style for the selected post's content
    selectedPostContent: {
        fontSize: 16, // Slightly larger font size
        textAlign: 'justify', // Justified text alignment
    },
    // Style for the back button in the selected post view
    backButton: {
        alignSelf: 'flex-end', // Align to the right
        marginTop: 20, // Space above the button
    },
    // Style for the back button text
    backButtonText: {
        color: 'blue', // Blue text color
        fontSize: 16, // Medium font size
    },
    // Container for the form (add/edit post)
    formContainer: {
        padding: 20, // Padding inside the form
        borderWidth: 1, // Border thickness
        borderColor: '#ccc', // Light gray border color
        borderRadius: 10, // Rounded corners
        marginBottom: 20, // Space below the form
    },
    // Style for text input fields
    input: {
        borderWidth: 1, // Border thickness
        borderColor: '#ccc', // Light gray border color
        padding: 10, // Padding inside the input
        marginBottom: 10, // Space below the input
        borderRadius: 5, // Slightly rounded corners
    },
    // Additional style for multi-line text area
    textArea: {
        height: 100, // Set height for text area
    },
    // Style for error messages
    errorText: {
        color: 'red', // Red text color
        textAlign: 'center', // Centered text
        marginBottom: 10, // Space below the error message
    },
});


- data: Create a global data variable that consists of a list of id, title, and content.

JavaScript
// Define initial blog post data as an array of objects
const data = [
    {
        id: 1, // Unique identifier for the post
        title: 'React', // Title of the post
        content: `ReactJS is a declarative, efficient, and flexible JavaScript library for building user interfaces.` // Content of the post
    },
    {
        id: 2, // Unique identifier for the post
        title: 'React Native', // Title of the post
        content: `It is a framework developed by Facebook for creating native-style apps for iOS & Android.` // Content of the post
    },
    // Add more blog posts here if needed
];


- Add New Post UI: Below is the UI code for the "Add New Post" form.

JavaScript
{/* Add new post form (only if not viewing or editing) */}
{selectedPost === null && editingPost === null && (
<View style={styles.formContainer}>
    {/* Error message */}
    {error !== '' &&
        <Text style={styles.errorText}>
            {error}
        </Text>}
    {/* Title input */}
    <TextInput
        style={styles.input}
        placeholder="Enter Title"
        value={newPostTitle}
        onChangeText={setNewPostTitle}
    />
    {/* Content input */}
    <TextInput
        style={[styles.input, styles.textArea]}
        placeholder="Enter Content"
        value={newPostContent}
        onChangeText={setNewPostContent}
        multiline={true}
    />
    {/* Add post button */}
    <Button title="Add New Post"
        onPress={() => addNewPost()} />
</View>


- addNewPost function: Below is the code to add a new post to the list.

JavaScript
// Function to add a new post to the list
const addNewPost = () => {
    // Validate that title and content are not empty
    if (newPostTitle.trim() === '' ||
        newPostContent.trim() === '') {
        setError('Title and content cannot be empty');
        return;
    } else {
        setError('');
    }

    // Generate a unique id for the new post
    const id = posts.length > 0 ? Math.max(...posts.map(p => p.id)) + 1 : 1;
    // Create the new post object
    const newPost =
    {
        id, title: newPostTitle,
        content: newPostContent
    };
    // Add the new post to the posts array
    setPosts([...posts, newPost]);
    // Clear the input fields
    setNewPostTitle('');
    setNewPostContent('');
};


- Display blogs UI: Below is the code to display a list of blogs and rendered every item using renderItem function.

JavaScript
{/* List of posts (only if not viewing or editing) */}
{!selectedPost && !editingPost ? (
    <FlatList
        data={posts}
        renderItem={renderItem}
        keyExtractor={(item) => item.id.toString()}
    />
) : null}


- renderItem function: This function is used to render every item or blog post, which consists of title, content, edit button and delete button.

JavaScript
// Function to render each post item in the FlatList
const renderItem = ({ item }) => (
    <TouchableOpacity
        onPress={() => setSelectedPost(item)} // Show post details on press
    >
        <View style={styles.postContainer}>
            <Text style={styles.postTitle}>
                {item.title}
            </Text>
            <View
                style={{ width: 280 }}
            >
                <Text style={styles.postContent}>
                    {item.content}
                </Text>
            </View>
            <View style={{
                flexDirection: 'row',
                alignSelf: 'flex-end'
            }}>
                {/* Edit button */}
                <TouchableOpacity style={styles.deleteButton}
                    onPress={() => handleEdit(item)}>
                    <Text style={styles.editButtonText}>
                        Edit .
                    </Text>
                </TouchableOpacity>
                {/* Delete button */}
                <TouchableOpacity style={styles.deleteButton}
                    onPress={() => deletePost(item.id)}>
                    <Text style={styles.deleteButtonText}>
                        Delete .
                    </Text>
                </TouchableOpacity>
            </View>
        </View>
    </TouchableOpacity>
);


- Detailed View Post: Below is the code to display the post in a detailed way when the user taps on any post.

JavaScript
{/* Selected post details view */}
{selectedPost && !editingPost && (
<View style={styles.selectedPostContainer}>
    <Text style={styles.selectedPostTitle}>
        {selectedPost.title}
    </Text>
    <Text style={styles.selectedPostContent}>
        {selectedPost.content}
    </Text>
    {/* Back button to return to list */}
    <TouchableOpacity style={styles.backButton}
        onPress={() => setSelectedPost(null)}>
        <Text style={styles.backButtonText}>
            Back .
        </Text>
    </TouchableOpacity>
</View>


- updatePost & deletePost functions:

JavaScript
// Function to delete a post by its id
const deletePost = (postId) => {
    // Filter out the post with the given id
    const updatedPosts =
        posts.filter(
            (post) =>
                post.id !== postId);
    // Update the posts state
    setPosts(updatedPosts);
};

// Function to update a post's title and content
const updatePost = (postId, updatedTitle, updatedContent) => {
    // Map through posts and update the matching post
    setPosts(posts.map(post =>
        post.id === postId
            ? { ...post, title: updatedTitle, content: updatedContent }
            : post
    ));
};

// Function to start editing a post
const handleEdit = (post) => {
    setEditingPost(post); // Set the post being edited
    setEditingTitle(post.title); // Set the editing title input
    setEditingContent(post.content); // Set the editing content input
    setError(''); // Clear any error
};

// Function to save the edited post
const handleSaveEdit = () => {
    // Validate that title and content are not empty
    if (editingTitle.trim() === '' || editingContent.trim() === '') {
        setError('Title and content cannot be empty');
        return;
    }
    // Update the post in the posts array
    updatePost(editingPost.id, editingTitle, editingContent);
    // Reset editing states
    setEditingPost(null);
    setEditingTitle('');
    setEditingContent('');
    setError('');
};

// Function to cancel editing
const handleCancelEdit = () => {
    setEditingPost(null); // Clear editing post
    setEditingTitle(''); // Clear editing title
    setEditingContent(''); // Clear editing content
    setError(''); // Clear error
};


- useState: Used to manage the state of the variables, written in the code below.

JavaScript
// State for the currently selected post (for viewing details)
const [selectedPost, setSelectedPost] = useState(null);
// State for the new post's title input
const [newPostTitle, setNewPostTitle] = useState('');
// State for the new post's content input
const [newPostContent, setNewPostContent] = useState('');
// State for the list of posts
const [posts, setPosts] = useState(data);
// State for error messages
const [error, setError] = useState('');

// State for the post being edited (null if not editing)
const [editingPost, setEditingPost] = useState(null);
// State for the editing post's title input
const [editingTitle, setEditingTitle] = useState('');
// State for the editing post's content input
const [editingContent, setEditingContent] = useState('');


Complete Source Code

App.js:

App.js
// Import the useState hook from React for managing state in functional components
import { useState } from 'react';
// Import core React Native components for building the UI
import {
    View,           // Container component for layout
    Button,         // Button component for user actions
    TextInput,      // Input field for text entry
    Text,           // Component for displaying text
    FlatList,       // Efficient list view for rendering posts
    StyleSheet,     // Utility for creating component styles
    TouchableOpacity // Wrapper for making views touchable
} from 'react-native';

// Define initial blog post data as an array of objects
const data = [
    {
        id: 1, // Unique identifier for the post
        title: 'React', // Title of the post
        content: `ReactJS is a declarative, efficient, and flexible JavaScript library for building user interfaces.` // Content of the post
    },
    {
        id: 2, // Unique identifier for the post
        title: 'React Native', // Title of the post
        content: `It is a framework developed by Facebook for creating native-style apps for iOS & Android.` // Content of the post
    },
    // Add more blog posts here if needed
];

const App = () => {
    // State for the currently selected post (for viewing details)
    const [selectedPost, setSelectedPost] = useState(null);
    // State for the new post's title input
    const [newPostTitle, setNewPostTitle] = useState('');
    // State for the new post's content input
    const [newPostContent, setNewPostContent] = useState('');
    // State for the list of posts
    const [posts, setPosts] = useState(data);
    // State for error messages
    const [error, setError] = useState('');

    // State for the post being edited (null if not editing)
    const [editingPost, setEditingPost] = useState(null);
    // State for the editing post's title input
    const [editingTitle, setEditingTitle] = useState('');
    // State for the editing post's content input
    const [editingContent, setEditingContent] = useState('');

    // Function to add a new post to the list
    const addNewPost = () => {
        // Validate that title and content are not empty
        if (newPostTitle.trim() === '' ||
            newPostContent.trim() === '') {
            setError('Title and content cannot be empty');
            return;
        } else {
            setError('');
        }

        // Generate a unique id for the new post
        const id = posts.length > 0 ? Math.max(...posts.map(p => p.id)) + 1 : 1;
        // Create the new post object
        const newPost =
        {
            id, title: newPostTitle,
            content: newPostContent
        };
        // Add the new post to the posts array
        setPosts([...posts, newPost]);
        // Clear the input fields
        setNewPostTitle('');
        setNewPostContent('');
    };

    // Function to delete a post by its id
    const deletePost = (postId) => {
        // Filter out the post with the given id
        const updatedPosts =
            posts.filter(
                (post) =>
                    post.id !== postId);
        // Update the posts state
        setPosts(updatedPosts);
    };

    // Function to update a post's title and content
    const updatePost = (postId, updatedTitle, updatedContent) => {
        // Map through posts and update the matching post
        setPosts(posts.map(post =>
            post.id === postId
                ? { ...post, title: updatedTitle, content: updatedContent }
                : post
        ));
    };

    // Function to start editing a post
    const handleEdit = (post) => {
        setEditingPost(post); // Set the post being edited
        setEditingTitle(post.title); // Set the editing title input
        setEditingContent(post.content); // Set the editing content input
        setError(''); // Clear any error
    };

    // Function to save the edited post
    const handleSaveEdit = () => {
        // Validate that title and content are not empty
        if (editingTitle.trim() === '' || editingContent.trim() === '') {
            setError('Title and content cannot be empty');
            return;
        }
        // Update the post in the posts array
        updatePost(editingPost.id, editingTitle, editingContent);
        // Reset editing states
        setEditingPost(null);
        setEditingTitle('');
        setEditingContent('');
        setError('');
    };

    // Function to cancel editing
    const handleCancelEdit = () => {
        setEditingPost(null); // Clear editing post
        setEditingTitle(''); // Clear editing title
        setEditingContent(''); // Clear editing content
        setError(''); // Clear error
    };

    // Function to render each post item in the FlatList
    const renderItem = ({ item }) => (
        <TouchableOpacity
            onPress={() => setSelectedPost(item)} // Show post details on press
        >
            <View style={styles.postContainer}>
                <Text style={styles.postTitle}>
                    {item.title}
                </Text>
                <View
                    style={{ width: 280 }}
                >
                    <Text style={styles.postContent}>
                        {item.content}
                    </Text>
                </View>
                <View style={{
                    flexDirection: 'row',
                    alignSelf: 'flex-end'
                }}>
                    {/* Edit button */}
                    <TouchableOpacity style={styles.deleteButton}
                        onPress={() => handleEdit(item)}>
                        <Text style={styles.editButtonText}>
                            Edit .
                        </Text>
                    </TouchableOpacity>
                    {/* Delete button */}
                    <TouchableOpacity style={styles.deleteButton}
                        onPress={() => deletePost(item.id)}>
                        <Text style={styles.deleteButtonText}>
                            Delete .
                        </Text>
                    </TouchableOpacity>
                </View>
            </View>
        </TouchableOpacity>
    );

    // Main render
    return (
        <View style={styles.container}>
            {/* App heading */}
            <View style={styles.headingContainer}>
                <Text style={styles.heading}>Blog App</Text>
            </View>
            {/* List of posts (only if not viewing or editing) */}
            {!selectedPost && !editingPost ? (
                <FlatList
                    data={posts}
                    renderItem={renderItem}
                    keyExtractor={(item) => item.id.toString()}
                />
            ) : null}
            {/* Selected post details view */}
            {selectedPost && !editingPost && (
                <View style={styles.selectedPostContainer}>
                    <Text style={styles.selectedPostTitle}>
                        {selectedPost.title}
                    </Text>
                    <Text style={styles.selectedPostContent}>
                        {selectedPost.content}
                    </Text>
                    {/* Back button to return to list */}
                    <TouchableOpacity style={styles.backButton}
                        onPress={() => setSelectedPost(null)}>
                        <Text style={styles.backButtonText}>
                            Back .
                        </Text>
                    </TouchableOpacity>
                </View>
            )}
            {/* Edit post form */}
            {editingPost && (
                <View style={styles.formContainer}>
                    <Text style={styles.heading}>Edit Post</Text>
                    {/* Error message */}
                    {error !== '' &&
                        <Text style={styles.errorText}>
                            {error}
                        </Text>}
                    {/* Title input */}
                    <TextInput
                        style={styles.input}
                        placeholder="Enter Title"
                        value={editingTitle}
                        onChangeText={setEditingTitle}
                    />
                    {/* Content input */}
                    <TextInput
                        style={[styles.input, styles.textArea]}
                        placeholder="Enter Content"
                        value={editingContent}
                        onChangeText={setEditingContent}
                        multiline={true}
                    />
                    {/* Save and Cancel buttons */}
                    <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
                        <Button title="Save" onPress={handleSaveEdit} />
                        <Button title="Cancel" color="grey" onPress={handleCancelEdit} />
                    </View>
                </View>
            )}
            {/* Add new post form (only if not viewing or editing) */}
            {selectedPost === null && editingPost === null && (
                <View style={styles.formContainer}>
                    {/* Error message */}
                    {error !== '' &&
                        <Text style={styles.errorText}>
                            {error}
                        </Text>}
                    {/* Title input */}
                    <TextInput
                        style={styles.input}
                        placeholder="Enter Title"
                        value={newPostTitle}
                        onChangeText={setNewPostTitle}
                    />
                    {/* Content input */}
                    <TextInput
                        style={[styles.input, styles.textArea]}
                        placeholder="Enter Content"
                        value={newPostContent}
                        onChangeText={setNewPostContent}
                        multiline={true}
                    />
                    {/* Add post button */}
                    <Button title="Add New Post"
                        onPress={() => addNewPost()} />
                </View>
            )}
        </View>
    );
};

// Define styles for the components using StyleSheet.create
const styles = StyleSheet.create({
    // Main container style for the app
    container: {
        flex: 1, // Take up the full screen
        paddingTop: 40, // Space from the top
        paddingHorizontal: 20, // Space on left and right
    },
    // Container for the heading section
    headingContainer: {
        backgroundColor: '#3498db', // Blue background
        padding: 10, // Padding inside the container
        borderRadius: 10, // Rounded corners
        marginBottom: 20, // Space below the heading
    },
    // Style for the main heading text
    heading: {
        fontSize: 24, // Large font size
        fontWeight: 'bold', // Bold text
        textAlign: 'center', // Centered text
        color: 'white', // White text color
    },
    // Container for each blog post
    postContainer: {
        borderWidth: 1, // Border thickness
        borderColor: '#ccc', // Light gray border color
        padding: 20, // Padding inside the post
        marginBottom: 20, // Space below each post
        borderRadius: 10, // Rounded corners
    },
    // Style for the post title
    postTitle: {
        fontSize: 18, // Medium-large font size
        fontWeight: 'bold', // Bold text
        marginBottom: 10, // Space below the title
    },
    // Style for the post content text
    postContent: {
        fontSize: 14, // Normal font size
        textAlign: 'left', // Left-aligned text
    },
    // Style for the delete/edit button container
    deleteButton: {
        alignSelf: 'flex-end', // Align to the right
        marginTop: 10, // Space above the button
    },
    // Style for the edit button text
    editButtonText: {
        color: 'green', // Green text color
    },
    // Style for the delete button text
    deleteButtonText: {
        color: 'red', // Red text color
    },
    // Container for the selected post view
    selectedPostContainer: {
        padding: 20, // Padding inside the container
        marginBottom: 20, // Space below the container
        borderWidth: 1, // Border thickness
        borderColor: '#ccc', // Light gray border color
        borderRadius: 10, // Rounded corners
    },
    // Style for the selected post's title
    selectedPostTitle: {
        fontSize: 24, // Large font size
        fontWeight: 'bold', // Bold text
        marginBottom: 10, // Space below the title
    },
    // Style for the selected post's content
    selectedPostContent: {
        fontSize: 16, // Slightly larger font size
        textAlign: 'justify', // Justified text alignment
    },
    // Style for the back button in the selected post view
    backButton: {
        alignSelf: 'flex-end', // Align to the right
        marginTop: 20, // Space above the button
    },
    // Style for the back button text
    backButtonText: {
        color: 'blue', // Blue text color
        fontSize: 16, // Medium font size
    },
    // Container for the form (add/edit post)
    formContainer: {
        padding: 20, // Padding inside the form
        borderWidth: 1, // Border thickness
        borderColor: '#ccc', // Light gray border color
        borderRadius: 10, // Rounded corners
        marginBottom: 20, // Space below the form
    },
    // Style for text input fields
    input: {
        borderWidth: 1, // Border thickness
        borderColor: '#ccc', // Light gray border color
        padding: 10, // Padding inside the input
        marginBottom: 10, // Space below the input
        borderRadius: 5, // Slightly rounded corners
    },
    // Additional style for multi-line text area
    textArea: {
        height: 100, // Set height for text area
    },
    // Style for error messages
    errorText: {
        color: 'red', // Red text color
        textAlign: 'center', // Centered text
        marginBottom: 10, // Space below the error message
    },
});

export default App;


Output:



Next Article

Similar Reads