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
// 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;
|
// 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;
|
// 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;
|
// 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;
|
// 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: