React Native Spring Boot: Full-stack CRUD example

Here's a full-stack CRUD example using React Native as the front-end and Spring Boot 3 as the back-end. This example covers the setup and integration to manage tasks in a simple to-do list application.


1. Spring Boot Back-End

Add Dependencies to pom.xml

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>
</dependencies>

Configure H2 Database in application.properties

spring.datasource.url=jdbc:h2:mem:tasksdb
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.enabled=true
spring.jpa.hibernate.ddl-auto=update

Create Task Entity

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
public class Task {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private boolean completed;

    // Getters and Setters
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public boolean isCompleted() { return completed; }
    public void setCompleted(boolean completed) { this.completed = completed; }
}

Create TaskRepository

import org.springframework.data.jpa.repository.JpaRepository;

public interface TaskRepository extends JpaRepository<Task, Long> {
}

Create TaskController

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/tasks")
@CrossOrigin(origins = "*") // Allow all origins for CORS
public class TaskController {

    @Autowired
    private TaskRepository taskRepository;

    @GetMapping
    public List<Task> getAllTasks() {
        return taskRepository.findAll();
    }

    @PostMapping
    public Task createTask(@RequestBody Task task) {
        return taskRepository.save(task);
    }

    @PutMapping("/{id}")
    public Task updateTask(@PathVariable Long id, @RequestBody Task updatedTask) {
        Task task = taskRepository.findById(id).orElseThrow();
        task.setName(updatedTask.getName());
        task.setCompleted(updatedTask.isCompleted());
        return taskRepository.save(task);
    }

    @DeleteMapping("/{id}")
    public void deleteTask(@PathVariable Long id) {
        taskRepository.deleteById(id);
    }
}

2. React Native Front-End

Install Required Libraries

Run the following commands to create a React Native app and install dependencies:

npx react-native init TaskManager
cd TaskManager
npm install axios react-native-paper react-navigation

Create TaskService for API Calls

In the src/services/TaskService.js file:

import axios from 'axios';

const API_URL = 'http://10.0.2.2:8080/api/tasks'; // Use 127.0.0.1 for iOS or 10.0.2.2 for Android emulator

export const getTasks = () => axios.get(API_URL);
export const createTask = (task) => axios.post(API_URL, task);
export const updateTask = (id, task) => axios.put(`${API_URL}/${id}`, task);
export const deleteTask = (id) => axios.delete(`${API_URL}/${id}`);

Implement React Native Components

  1. TaskList Component

src/components/TaskList.js:

import React, { useEffect, useState } from 'react';
import { View, FlatList, Text, Button, TextInput } from 'react-native';
import { getTasks, createTask, updateTask, deleteTask } from '../services/TaskService';

const TaskList = () => {
    const [tasks, setTasks] = useState([]);
    const [newTaskName, setNewTaskName] = useState('');

    useEffect(() => {
        fetchTasks();
    }, []);

    const fetchTasks = async () => {
        const response = await getTasks();
        setTasks(response.data);
    };

    const addTask = async () => {
        if (newTaskName) {
            await createTask({ name: newTaskName, completed: false });
            setNewTaskName('');
            fetchTasks();
        }
    };

    const toggleTaskCompletion = async (task) => {
        await updateTask(task.id, { ...task, completed: !task.completed });
        fetchTasks();
    };

    const removeTask = async (id) => {
        await deleteTask(id);
        fetchTasks();
    };

    return (
        <View style={{ padding: 16 }}>
            <TextInput
                placeholder="New Task"
                value={newTaskName}
                onChangeText={setNewTaskName}
                style={{ borderBottomWidth: 1, marginBottom: 8 }}
            />
            <Button title="Add Task" onPress={addTask} />
            <FlatList
                data={tasks}
                keyExtractor={(item) => item.id.toString()}
                renderItem={({ item }) => (
                    <View style={{ flexDirection: 'row', justifyContent: 'space-between', marginVertical: 8 }}>
                        <Text style={{ textDecorationLine: item.completed ? 'line-through' : 'none' }}>
                            {item.name}
                        </Text>
                        <View style={{ flexDirection: 'row' }}>
                            <Button title={item.completed ? 'Undo' : 'Complete'} onPress={() => toggleTaskCompletion(item)} />
                            <Button title="Delete" onPress={() => removeTask(item.id)} />
                        </View>
                    </View>
                )}
            />
        </View>
    );
};

export default TaskList;

  1. App Component

App.js:

import React from 'react';
import { SafeAreaView } from 'react-native';
import TaskList from './src/components/TaskList';

const App = () => {
    return (
        <SafeAreaView>
            <TaskList />
        </SafeAreaView>
    );
};

export default App;

3. Running the Application

  1. Start Spring Boot Server: Run the server using:

    mvn spring-boot:run
  2. Run React Native App: Start the React Native app on an emulator or physical device:

    npx react-native run-android
    # OR
    npx react-native run-ios
  3. Test the App:

    • Add new tasks.
    • Mark tasks as completed.
    • Delete tasks.

Popular posts from this blog

Learn Java 8 streams with an example - print odd/even numbers from Array and List

Java Stream API - How to convert List of objects to another List of objects using Java streams?

Registration and Login with Spring Boot + Spring Security + Thymeleaf

Java, Spring Boot Mini Project - Library Management System - Download

ReactJS, Spring Boot JWT Authentication Example

Top 5 Java ORM tools - 2024

Java - Blowfish Encryption and decryption Example

Spring boot video streaming example-HTML5

Google Cloud Storage + Spring Boot - File Upload, Download, and Delete