In this article, we’ll walk you through the process of building a basic Task Manager app using React Native. The application enables users to effortlessly create, edit, complete/incomplete, and delete tasks, providing an uncomplicated yet impactful introduction to React Native’s mobile app development capabilities.
Prerequisites
- Introduction to React Native
- Javascript
- React Native State
- React Native Props
- Expo CLI
- Node.js and npm (Node Package Manager)
Steps to install & configure React Native
Step 1: Create a react native application by using this command:
npx create-expo-app taskmanager-app
Step 2: After creating your project folder, i.e. taskmanager-app, use the following command to navigate to it:
cd taskmanager-app
Step 2: Use an external library for a Date Picker
In this App, we have installed react native modern date picker for selecting dates.
npm i react-native-modern-datepicker
Project structure
Approach
This code snippet in React Native allows you to build a simple taskmanager app effortlessly. It effectively manages the state using useState, enabling you to handle task data, editing functionality, and modal visibility smoothly. The app’s interface presents a scrollable list of tasks, each featuring a title. By utilizing modals with title and content inputs, users can easily add, edit,complete/incomplete and delete tasks.
Example: This example creates a Task Manager App using react-native
Javascript
// App.js // Import necessary modules and components import React, { useState } from "react" ; import { View, Text, TouchableOpacity, Modal, Button, } from "react-native" ; // Import TaskList component import TaskList from "./components/TaskList" ; // Import TaskModal component import TaskModal from "./components/TaskModel" ; import styles from "./styles" ; // Import styles // Define the main App component const App = () => { // Define state variables // Array to store tasks const [tasks, setTasks] = useState([]); const [task, setTask] = useState({ title: "" , description: "" , status: "Pending" , deadline: "" , createdAt: "" , }); // Task object for creating/editing tasks // Modal visibility const [modalVisible, setModalVisible] = useState( false ); // Task being edited const [editingTask, setEditingTask] = useState( null ); const [validationError, setValidationError] = useState( false ); // Validation flag // Function to add a new task or update an existing task const handleAddTask = () => { if ( task.title.trim() !== "" && task.deadline !== "" ) { const currentDate = new Date(); const formattedDate = currentDate.toLocaleString(); if (editingTask) { // If editing an existing task, update it const updatedTasks = tasks.map((t) => t.id === editingTask.id ? { ...t, ...task } : t ); setTasks(updatedTasks); setEditingTask( null ); } else { // If adding a new task, create it const newTask = { id: Date.now(), ...task, // Set the creation date and time as a string createdAt: formattedDate, }; setTasks([...tasks, newTask]); } // Clear the task input fields and reset state setTask({ title: "" , description: "" , status: "Pending" , deadline: "" , createdAt: "" , }); // Close the modal setModalVisible( false ); // Reset validation error setValidationError( false ); } else { // Show validation error if fields are not filled setValidationError( true ); } }; // Function to handle task editing const handleEditTask = (task) => { // Set the task being edited setEditingTask(task); // Pre-fill the input with task data setTask(task); // Open the modal for editing setModalVisible( true ); }; // Function to delete a task const handleDeleteTask = (taskId) => { const updatedTasks = tasks.filter( (t) => t.id !== taskId ); setTasks(updatedTasks); }; // Function to toggle task completion status const handleToggleCompletion = (taskId) => { const updatedTasks = tasks.map((t) => t.id === taskId ? { ...t, status: t.status === "Pending" ? "Completed" : "Pending" , } : t ); setTasks(updatedTasks); }; // Return the JSX for rendering the component return ( <View style={styles.container}> <Text style={styles.title}>Task Manager</Text> { /* Render the TaskList component */ } <TaskList tasks={tasks} handleEditTask={handleEditTask} handleToggleCompletion={ handleToggleCompletion } handleDeleteTask={handleDeleteTask} /> { /* Button to add or edit tasks */ } <TouchableOpacity style={styles.addButton} onPress={() => { setEditingTask( null ); setTask({ title: "" , description: "" , status: "Pending" , deadline: "" , createdAt: "" , }); setModalVisible( true ); setValidationError( false ); }}> <Text style={styles.addButtonText}> {editingTask ? "Edit Task" : "Add Task" } </Text> </TouchableOpacity> { /* Render the TaskModal component */ } <TaskModal modalVisible={modalVisible} task={task} setTask={setTask} handleAddTask={handleAddTask} handleCancel={() => { setEditingTask( null ); setTask({ title: "" , description: "" , status: "Pending" , deadline: "" , createdAt: "" , }); setModalVisible( false ); setValidationError( false ); }} validationError={validationError}/> </View> ); }; // Export the App component as the default export export default App; |
Javascript
// components/TaskList.js import React from "react" ; import { ScrollView } from "react-native" ; import TaskItem from "./TaskItem" ; import styles from "../styles" ; const TaskList = ({ tasks, handleEditTask, handleToggleCompletion, handleDeleteTask, }) => { return ( <ScrollView style={styles.taskList}> { /* Scrollable container for the list of tasks */ } {tasks.map((t) => ( <TaskItem // Use the task's ID as the key to // uniquely identify each TaskItem key={t.id} // Pass the task object as a prop to TaskItem task={t} // Pass functions to handle editing, // toggling completion, and deletion handleEditTask={handleEditTask} handleToggleCompletion={ handleToggleCompletion } handleDeleteTask={handleDeleteTask} /> ))} </ScrollView> ); }; // Export the TaskList component export default TaskList; |
Javascript
// components/TaskItem.js import React from "react" ; import { View, Text, TouchableOpacity } from "react-native" ; import styles from "../styles" ; const TaskItem = ({ task, handleEditTask, handleToggleCompletion, handleDeleteTask, }) => { return ( <View style={styles.taskItem}> <View style={styles.taskTextContainer}> <Text style={[ styles.taskText, task.status === "Completed" && styles.completedTaskText, ]}> {task.title} </Text> <Text style={styles.taskDescription}> {task.description} </Text> <Text style={styles.taskStatus}> Status: {task.status} </Text> <Text style={styles.taskDeadline}> Deadline: {task.deadline} </Text> <Text style={styles.taskCreatedAt}> Created: {task.createdAt} </Text> </View> <View style={styles.buttonContainer}> <TouchableOpacity onPress={() => handleEditTask(task)} style={[styles.editButton]}> <Text style={styles.buttonText}> Edit </Text> </TouchableOpacity> <TouchableOpacity onPress={() => handleToggleCompletion(task.id) } style={[ styles.completeButton, task.status === "Completed" && styles.completedButton, ]}> <Text style={styles.buttonText}> {task.status === "Completed" ? "Pending" : "Completed" } </Text> </TouchableOpacity> <TouchableOpacity onPress={() => handleDeleteTask(task.id) } style={[styles.deleteButton]}> <Text style={styles.buttonText}> Delete </Text> </TouchableOpacity> </View> </View> ); }; export default TaskItem; |
Javascript
// components/TaskModal.js import React from "react" ; import { View, Text, TextInput, Button, Modal, } from "react-native" ; import styles from "../styles" ; import DatePicker from "react-native-modern-datepicker" ; const TaskModal = ({ modalVisible, task, setTask, handleAddTask, handleCancel, validationError, }) => { return ( <Modal visible={modalVisible} animationType= "slide" transparent={ false }> { /* Container for the modal */ } <View style={styles.modalContainer}> <TextInput style={styles.input} placeholder= "Title" value={task.title} onChangeText={(text) => setTask({ ...task, title: text }) } // Update the title when text changes/> <TextInput style={styles.input} placeholder= "Description" value={task.description} onChangeText={(text) => setTask({ ...task, description: text, }) }/> <Text style={styles.inputLabel}> Deadline: </Text> <DatePicker style={styles.datePicker} mode= "date" selected={task.deadline} onDateChange={(date) => setTask({ ...task, deadline: date }) }/> {validationError && ( <Text style={styles.errorText}> Please fill in all fields correctly. </Text> )} <Button // Display "Update" when editing an existing // task, "Add" when adding a new task title={task.id ? "Update" : "Add" } // Call the handleAddTask function // when the button is pressed onPress={handleAddTask} // Set the button color color= "#007BFF" /> <Button title= "Cancel" onPress={handleCancel} color= "#FF3B30" /> </View> </Modal> ); }; export default TaskModal; |
Javascript
// styles.js import { StyleSheet } from "react-native" ; const styles = StyleSheet.create({ container: { flex: 1, padding: 20, backgroundColor: "#f7f7f7" , }, title: { fontSize: 28, fontWeight: "bold" , marginBottom: 20, color: "#333" , textAlign: "center" , }, taskList: { flex: 1, }, taskItem: { flexDirection: "row" , justifyContent: "space-between" , alignItems: "center" , backgroundColor: "#fff" , marginBottom: 10, padding: 15, borderRadius: 10, }, taskTextContainer: { flex: 1, }, taskText: { fontSize: 18, fontWeight: "bold" , color: "#333" , }, completedTaskText: { textDecorationLine: "line-through" , color: "gray" , }, taskDescription: { fontSize: 16, color: "#666" , }, taskTime: { fontSize: 14, color: "#666" , }, taskStatus: { fontSize: 16, color: "#666" , }, buttonContainer: { // Or 'row' depending on your layout flexDirection: "column" , // Adjust the value as needed for the // desired spacing marginVertical: 2, }, editButton: { backgroundColor: "#007BFF" , borderRadius: 5, padding: 10, marginRight: 10, width: 110, }, button: { marginBottom: 10, }, completeButton: { backgroundColor: "#4CAF50" , borderRadius: 5, padding: 10, marginRight: 10, width: 110, }, completedButton: { backgroundColor: "#808080" , }, buttonText: { color: "#fff" , fontSize: 15, }, deleteButton: { backgroundColor: "#FF9500" , borderRadius: 5, padding: 10, width: 110, }, addButton: { alignItems: "center" , justifyContent: "center" , backgroundColor: "#007BFF" , paddingVertical: 15, borderRadius: 10, marginTop: 20, }, addButtonText: { color: "#fff" , fontSize: 18, fontWeight: "bold" , }, modalContainer: { flex: 1, padding: 20, backgroundColor: "#fff" , }, input: { borderWidth: 1, borderColor: "#ccc" , padding: 10, marginBottom: 20, borderRadius: 5, fontSize: 16, }, inputLabel: { fontSize: 16, fontWeight: "bold" , }, errorText: { color: "#FF3B30" , fontSize: 16, marginBottom: 10, }, taskDeadline: { color: "#FF3B12" , }, taskCreatedAt: { color: "#5497FF" , }, }); export default styles; |
Steps to Run
Go to the Terminal and type the following command to run the react native application.
npx expo start
To run on Android:
npx react-native run-android
To run on iOS:
npx react-native run-ios
Output: