Topics -> react-native, appdevelopment, expo-client, todoapp
Preview Link -> TodoApp
Source Code Link -> GitHub
What We are going to do?
- Creating a basic structure.
- Adding event handler/functions to add and delete task.
- Adding Some stylings.
Installation of React Native Project using Expo-client
Assuming that you have Node 12 LTS or greater installed, you can use npm to install the Expo CLI command line utility:
npm install -g expo-cli
Then run the following commands to create a new React Native project called "TodoApp":
expo init AwesomeProject cd AwesomeProject npm start # you can also use: expo start
Components
Create a Component folder and add these components to it.
Header (header.js)
It will shows the navbar/header of the app.
import React, { Component } from "react";
import {
StyleSheet,
Text,
View,
} from "react-native";
export default class header extends Component {
render() {
return (
<View style={styles.header}>
<Text style={styles.headerText}>Todo List</Text>
</View>
);
}
}
Stylings used in Header Component
const styles = StyleSheet.create({
header: {
height: 80,
backgroundColor: "#574b90",
paddingTop:40,
},
headerText:{
textAlign:'center',
fontSize:24,
color:'white'
}
});
Form Component (form.js)
This component will take the input from the user and add the task in TODO list.
import React, { Component } from "react";
import {
StyleSheet,
Text,
TextInput,
TouchableOpacity,
View,
Button,
} from "react-native";
export default class form extends Component {
constructor(props) {
super(props);
this.state = { todo: "" };
}
todoTextHandler = (val) => {
this.setState({ todo: val });
};
render() {
return (
<View>
<TextInput
multiline
placeholder="write a todo"
style={styles.todoInput}
onChangeText={this.todoTextHandler}
/>
<View style={styles.btn}>
<Button
title="Add todo"
color="#574b90"
onPress={() => {
console.log("todo", this.state.todo);
this.props.todoHandler(this.state.todo);
}}
/>
</View>
</View>
);
}
}
Stylings used in Form Component
const styles = StyleSheet.create({
todoInput: {
borderColor: "#9e579d",
backgroundColor:'#fc85ae',
color:'#574b90',
borderWidth: 3,
height: 80,
marginHorizontal: 20,
marginTop: 10,
textAlign: "center",
fontSize: 18,
fontWeight: "bold",
},
btn: {
marginTop: 20,
paddingHorizontal: 20,
},
});
TodoItem (todoItem.js)
This component will show all the tasks in TODO list and provide a delete button to delete them.
import React, { Component } from "react";
import { StyleSheet, Text, View } from "react-native";
import { MaterialIcons } from "@expo/vector-icons";
export default class todoItem extends Component {
constructor(props) {
super(props);
}
render() {
return (
<View style={styles.singleTodoContainer}>
<MaterialIcons
name="delete"
size={25}
onPress={() => this.props.todoRemoveHandler(this.props.item.key)}
/>
<Text style={styles.todoText}>{this.props.item.text}</Text>
</View>
);
}
}
Stylings used in Todo Component
const styles = StyleSheet.create({
todoText: {
flex:1,
color: "#cabbe9",
fontSize: 18,
flexWrap: "wrap",
},
singleTodoContainer: {
backgroundColor: "#9e579d",
borderRadius:25,
flexDirection: "row",
marginVertical: 10,
paddingVertical: 10,
textAlign: "center",
},
});
Editing the main App Component (App.js)
We will be adding event handlers to delete the tasks which are done
Importing required libraries
import { StatusBar } from "expo-status-bar";
import React, { useState } from "react";
import {
Button,
StyleSheet,
Text,
View,
TextInput,
ScrollView,
FlatList,
TouchableOpacity,
Alert,
Touchable,
ImageBackground,
Keyboard,
TouchableWithoutFeedback,
} from "react-native";
import Header from "./components/header";
import TodoItem from "./components/todoItem";
import Form from "./components/form";
Adding dummy tasks
export default function App() {
const [todo, setTodo] = useState([
{ text: "make readme.md", key: "1" },
{ text: "update readme.md", key: "2" },
{ text: "modify readme.md", key: "3" },
{ text: "delete readme.md", key: "4" },
]);
Adding conditionals to validate that the length of task must be 3.
const todoHandler = (task) => {
if (task.length > 3) {
setTodo((prevTodo) => {
return [{ text: task, key: Math.random().toString() }, ...prevTodo];
});
} else {
Alert.alert("OOPS!", "Todo must be 3 chars long", [
{ text: "UNDERSTOOD", onPress: () => console.log("alert closed") },
]);
}
};
Event Handlers for deleting Task
const todoRemoveHandler = (key) => {
setTodo((prevTodo) => {
return prevTodo.filter((todoitem) => todoitem.key != key);
});
};
Aligning the all components
return (
<TouchableWithoutFeedback
onPress={() => {
Keyboard.dismiss();
}}
>
<View style={styles.container}>
{/* header */}
<Header />
<ImageBackground source={require('./assets/backTodo.jpg')} style={styles.image}>
{/* form */}
<View>
<Form todoHandler={todoHandler} />
</View>
{/* container */}
<View style={styles.todoContainer}>
<FlatList
data={todo}
keyExtractor={(item) => {
return item.key;
}}
renderItem={({ item }) => (
<TodoItem item={item} todoRemoveHandler={todoRemoveHandler} />
)}
/>
</View>
{/* credits */}
<View style={styles.introduction}>
<Text style={styles.centerText}>
This app is created by Praveen Chaudhary
</Text>
</View>
</ImageBackground>
</View>
</TouchableWithoutFeedback>
);
}
Adding styles
const styles = StyleSheet.create({
container: {
flex: 1,
// backgroundColor: "#303a52",
},
todoContainer: {
paddingHorizontal: 20,
},
introduction: {
position: "absolute",
bottom: 0,
textAlign: "center",
left: 0,
right: 0,
paddingBottom: 10,
backgroundColor: "#574b90",
alignSelf: "stretch",
},
centerText: {
textAlign: "center",
fontSize: 16,
color: "#fc85ae",
},
image: {
flex: 1,
resizeMode: "cover",
},
btn: {
marginTop: 20,
paddingHorizontal: 20,
},
singleTodoContainer: {
flexDirection: "row",
},
});
All App Component together
import { StatusBar } from "expo-status-bar";
import React, { useState } from "react";
import {
Button,
StyleSheet,
Text,
View,
TextInput,
ScrollView,
FlatList,
TouchableOpacity,
Alert,
Touchable,
ImageBackground,
Keyboard,
TouchableWithoutFeedback,
} from "react-native";
import Header from "./components/header";
import TodoItem from "./components/todoItem";
import Form from "./components/form";
export default function App() {
const [todo, setTodo] = useState([
{ text: "make readme.md", key: "1" },
{ text: "update readme.md", key: "2" },
{ text: "modify readme.md", key: "3" },
{ text: "delete readme.md", key: "4" },
]);
const todoHandler = (task) => {
if (task.length > 3) {
setTodo((prevTodo) => {
return [{ text: task, key: Math.random().toString() }, ...prevTodo];
});
} else {
Alert.alert("OOPS!", "Todo must be 3 chars long", [
{ text: "UNDERSTOOD", onPress: () => console.log("alert closed") },
]);
}
};
const todoRemoveHandler = (key) => {
setTodo((prevTodo) => {
return prevTodo.filter((todoitem) => todoitem.key != key);
});
};
return (
<TouchableWithoutFeedback
onPress={() => {
Keyboard.dismiss();
}}
>
<View style={styles.container}>
{/* header */}
<Header />
<ImageBackground source={require('./assets/backTodo.jpg')} style={styles.image}>
{/* form */}
<View>
<Form todoHandler={todoHandler} />
</View>
{/* container */}
<View style={styles.todoContainer}>
<FlatList
data={todo}
keyExtractor={(item) => {
return item.key;
}}
renderItem={({ item }) => (
<TodoItem item={item} todoRemoveHandler={todoRemoveHandler} />
)}
/>
</View>
{/* credits */}
<View style={styles.introduction}>
<Text style={styles.centerText}>
This app is created by Praveen Chaudhary
</Text>
</View>
</ImageBackground>
</View>
</TouchableWithoutFeedback>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
// backgroundColor: "#303a52",
},
todoContainer: {
paddingHorizontal: 20,
},
introduction: {
position: "absolute",
bottom: 0,
textAlign: "center",
left: 0,
right: 0,
paddingBottom: 10,
backgroundColor: "#574b90",
alignSelf: "stretch",
},
centerText: {
textAlign: "center",
fontSize: 16,
color: "#fc85ae",
},
image: {
flex: 1,
resizeMode: "cover",
},
btn: {
marginTop: 20,
paddingHorizontal: 20,
},
singleTodoContainer: {
flexDirection: "row",
},
});
Deployment
For deployment, We are using the Expo. For More Info
Web Preview / Output
Web preview on deployment
Placeholder text by Praveen Chaudhary · Images by Binary Beast