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
Placeholder text by Praveen Chaudhary · Images by Binary Beast