How to setup React Native and create a simple To-Do App

yarn global add expo-cli
expo init todo-app
# select "blank (TypeScript)"
cd todo-app
yarn start
# press w to open the web app

Create a To-Do app

Prerequisites

yarn add react-native-bouncy-checkbox
./todo-app/
...
models/
todo.model.ts
components/
todo.tsx
todo-list.tsx
menu.tsx
views/
edit-todo.view.tsx
...

The Data Model

interface ITodo {
id: string
done: boolean
text: string
color: string
}
export default ITodo

Basic components

import React, { useState } from "react";
import { StyleSheet, Text, View } from 'react-native';
import BouncyCheckbox from "react-native-bouncy-checkbox";
import ITodo from "../models/todo.model";
interface ITodoProps {
data: ITodo
}
const Todo = (props: ITodoProps) => {
const [isDone, setDone] = useState(false);

return (
<View style={[styles.container, {backgroundColor: props.data.color}]}>
<BouncyCheckbox
fillColor="black"
unfillColor="#FFFFFF"
iconStyle={{ borderColor: "black" }}
isChecked={isDone}
onPress={setDone}
style={styles.checkbox}
/>

<Text style={styles.text}>{props.data.text}</Text>
</View>
);
}
export default Todoconst styles = StyleSheet.create({
container: {
width: '100%', minHeight: '30px', height: 'auto',
color: 'black',
alignItems: 'center',
justifyContent: 'flex-start',
display: 'flex',
flexDirection: 'row',
marginBottom: 5,
padding: 10,
borderRadius: 5,
},
checkbox: {
width: 40,
minWidth: 40, height: 40,
},
text: {
color: 'black',
width: '100%',
}
});
import React, { useState } from "react";
import { StyleSheet, FlatList } from 'react-native';
import ITodo from "../models/todo.model";
import Todo from "./todo";
interface ITodoListProps {
data: ITodo[]
}
const TodoList = (props: ITodoListProps) => {
const [isDone, setDone] = useState(false);

return (
<FlatList
style={styles.container}
data={props.data}
renderItem={
(item: any) => {
return (
<Todo data={item.item} />
)
}
}
keyExtractor={(item, index) => item.id}
/>
);
}
export default TodoListconst styles = StyleSheet.create({
container: {
// height: '100%', maxHeight: '100%',
height: 500,
width: '100%',
flexDirection: 'column',
padding: 10,
overflow: 'scroll',
},
});
import React, { useState } from "react";
import { Button, StyleSheet, Text, View } from 'react-native';
interface IMenu {
onAddTodo: () => void
}
const Menu = (props: IMenu) => {
return (
<View style={styles.container}>
<Button
title="+ Add ToDo"
onPress={() => props.onAddTodo()}/>
</View>
);
}
export default Menuconst styles = StyleSheet.create({
container: {
width: '100%', minHeight: '30px', height: 'auto',
color: 'black',
alignItems: 'center',
justifyContent: 'center',
display: 'flex',
flexDirection: 'row',
padding: 20,
},
});

Views

import React, { useState } from "react"
import { Modal, StyleSheet, TextInput, View, Text, TouchableOpacity, KeyboardAvoidingView } from 'react-native';
import ITodo from "../models/todo.model";
interface IEditTodoProps {
isVisible: boolean
onClose: () => void
onSave: (data: any) => void
data?: ITodo
}
const EditTodoView = (props: IEditTodoProps) => { const colors = ['#87D3F5', '#BDE991', '#BAAAFB']
const [colorIndex, setColorIndex] = useState(0)
const title = props.data ? 'Edit Todo' : 'Add Todo'
const [text, setText] = useState(props.data?.text || '')
const onSave = () => {
if (text.trim().length === 0) {
props.onClose()
return
}
if (props.data) {
const newData = {
...props.data,
text
}
props.onSave(newData)
} else {
const newData = {
id: 'id-' + Math.floor(Math.random() * 10000000),
text,
done: false,
color: colors[colorIndex],
}
props.onSave(newData)
}
}
return (
<Modal visible={props.isVisible} style={styles.modal}
animationType="slide"
transparent={true}
>
<KeyboardAvoidingView style={styles.container} >
<Text style={styles.title}>{title}</Text>
<View style={styles.content}>
<Text style={styles.label}>ToDo Text:</Text>
<TextInput
style={styles.input}
onChangeText={setText}
value={props.data?.text}
multiline={true}
numberOfLines={10}
// keyboardType="numeric"
/>
<Text style={styles.label}>ToDo Color:</Text>
<View style={styles.colors} >
<View style={[styles.color, {
backgroundColor: colors[0],
borderColor: 'black',
borderWidth: colorIndex === 0 ? 4 : 0
}]}
>
<TouchableOpacity
style={{height: '100%', width:'100%'}}
onPress={() => setColorIndex(0)}>
</TouchableOpacity>
</View>
<View style={[styles.color, {
backgroundColor: colors[1],
borderColor: 'black',
borderWidth: colorIndex === 1 ? 4 : 0}]}
>
<TouchableOpacity
style={{height: '100%', width:'100%'}}
onPress={() => setColorIndex(1)}>
</TouchableOpacity>
</View>
<View style={[styles.color, {
backgroundColor: colors[2],
borderColor: 'black',
borderWidth: colorIndex === 2 ? 4 : 0}]}
>
<TouchableOpacity
style={{height: '100%', width:'100%'}}
onPress={() => setColorIndex(2)}>
</TouchableOpacity>
</View>
</View>
</View>
<View style={styles.menu} >
<TouchableOpacity
style={styles.button}
onPress={() => props.onClose()}
>
<Text style={styles.buttonText}>Cancel</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.button}
onPress={onSave}
>
<Text style={styles.buttonText}>Save</Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
</Modal>
)
}
export default EditTodoView
const styles = StyleSheet.create({
modal: {
backgroundColor: 'rgba(0,0,0,0)',
},
container: {
width: '100%',
height: '100%',
paddingTop: 100,
// backgroundColor: '#fff',
backgroundColor: 'rgba(0,0,0,0.7)',
flexDirection: 'column',
},
content: {
backgroundColor: '#fff',
flexDirection: 'column',
},
title: {
fontSize: 24,
fontWeight: 'bold',
padding: 20,
paddingBottom: 0,
backgroundColor: '#fff',
},
menu: {
display: 'flex',
width: '100%', height: 60,
paddingLeft: 30,
paddingTop: 15,
flexDirection: 'row',
justifyContent: 'space-between',
backgroundColor: '#fff'
},
input: {
height: 'auto',
margin: 12,
borderWidth: 1,
padding: 10,
},
label: {
padding: 10,
paddingBottom: 0,
},
colors: {
width: '100%',
display: 'flex',
flexDirection: 'row',
padding: 20,
},
color: {
width: 30, height: 30,
marginRight: 20,
borderRadius: 3,
},
button: {
height: 20,
width: 100,
},
buttonText: {
fontSize: 18,
color: '#007fff'
}
});

Main View

import React, { useState } from 'react';
import { StyleSheet, Text, SafeAreaView } from 'react-native';
import Menu from './components/menu';
import TodoList from './components/todo-list';
import ITodo from './models/todo.model';
import EditTodoView from './views/edit-todo.view';
export default function App() { const [data, setData] = useState<ITodo[]>([])
const [isEditTodoVisible, setIsEditTodoVisible] = useState(false)
const onAddTodo = () => {
setIsEditTodoVisible(true)
}
const onCloseEditTodo = () => {
setIsEditTodoVisible(false)
}
const onSaveTodo = (data: ITodo) => {
setData((d) => [...d, data])
setIsEditTodoVisible(false)
}
return (
<SafeAreaView style={styles.container}>
<Text style={styles.title}>ToDo</Text>
<TodoList data={data} />
<Menu onAddTodo={onAddTodo}/>
<EditTodoView isVisible={isEditTodoVisible}
onClose={onCloseEditTodo}
onSave={onSaveTodo}
/>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
display: 'flex',
flexDirection: 'column',
backgroundColor: '#fff',
height: '100%',
width: '100%',
},
title: {
fontSize: 24,
fontWeight: 'bold',
padding: 20,
paddingBottom: 0,
},
});

--

--

--

https://alexadam.dev/

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Introduction of React Hooks

15 Useful NPM Packages That You Should Know

How to participate in buying Hebe

Azure Communication Service- Chat with File Sharing

JavaScript : Must Know Features (ECMAScript 2018)

Purpofy — Leading-edge web design to help you find out your purpose!

Creating Blog site using Stackbit, GatsbyJS and DEV -4

How Closures lead to Modules in JavaScript

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
alex adam

alex adam

https://alexadam.dev/

More from Medium

Is React Native a Good Choice for Mobile App Development?

Why Choose React Native To Develop Mobile Apps? Here Are The Reasons

Expo CLI vs React Native CLI

ReactNative: Basic App skeleton (For Beginner)