React native
React native Todo list 구현하기 #2
ji_su_04
2023. 1. 2. 19:16
1. 추가 기능 넣기.
이제 TodoList에 추가 기능을 넣어보자.
<TODOLIST.JSX>
const [todos, setTodos] = useState([]);
const [category, setCategory] = useState("Work"); // Work, Life, Want
const [text, setText] = useState("");
const newTodo = {
id: uuidv4(),
text,
isDone: false,
isEdit: false,
category,
};
//추가하기
const addTodo = () => {
setTodos((prev) => [...prev, newTodo]); //newTodo를 추가 하기 위해
setText("");
};
우선 useState를 추가해주자.
newTodo의 id는 uuidv4를 사용했는데 일반 리액트와 달리 리액트 네이티브에는 uuidv4를 사용하기 좀 까다로웠다.
npm install react-native-uuid
npm install react-native-get-random-values
npx pod-install
설치 후에 최상위 폴더에
import "react-native-get-random-values";
추가해주자.
그럼 다시 addTodo로 돌아가서 return의 input 부분에 이제 추가해야 할 코드를 확인해보자.
<TextInput
onSubmitEditing={addTodo}
onChangeText={setText}
value={text}
placeholder="Please write it here."
style={styles.input}
/>
TextInput에 onChangeText를 setText 값을 주고 value는 text를 넣자.
그 후에 onSubmitEditing에 맨 처음에 만든 addTodo를 넣고 투두리스트가 나오는 View 부분에 {todos.map((todo) =>{ key={todo.id} 를 준 후에 {todo.text}를 넣어주면 정상적으로 출력되는 것을 볼 수 있다.
2. 삭제 기능 넣기
이제 삭제 기능과 수정기능을 넣어보자.
//삭제하기
const removeTodo = (id) => {
Alert.alert("삭제", "정말 삭제 하시겠습니까?", [
{
text: "취소",
style: "cancle",
onPress: () => console.log("취소클릭"),
},
{
text: "삭제",
style: "destructive",
onPress: () => {
const newTodos = todos.filter((todo) => todo.id !== id);
setTodos(newTodos);
},
},
]);
};
//수정하기
const Edit = (id) => {
const newTodos = [...todos];
const idx = newTodos.findIndex((todo) => todo.id === id);
newTodos[idx].isEdit = !newTodos[idx].isEdit;
setTodos(newTodos);
};
const editTodo = (id) => {
// 1. id 값을 받아서 해당 배열 요소 찾음
// 2. todos[idx].text = editText로 바꿔줌
const newTodos = [...todos];
const idx = newTodos.findIndex((todo) => todo.id === id);
newTodos[idx].text = editText;
newTodos[idx].isEdit = false;
setTodos(newTodos);
seteditText("");
};
삭제하기에 Alert.alert 기능을 사용하면 삭제를 눌렀을 때 확인 알림 창이 뜨는데 매우 유용한 기능 같다.
수정하기는 isEdit가 초기에 false 값으로 부여 받았으니 이 값을 true로 바꿀 때 수정이 가능하게 만들어주면 된다.
id를 매개변수로 받고 id에 해당하는 배열의 요소를 찾는다.
import { StatusBar } from "expo-status-bar";
import {
SafeAreaView,
ScrollView,
StyleSheet,
Text,
TextInput,
TouchableOpacity,
View,
Image,
Alert,
} from "react-native";
import { AntDesign } from "@expo/vector-icons";
import { Feather } from "@expo/vector-icons";
import { MaterialCommunityIcons } from "@expo/vector-icons";
import { useState } from "react";
import { v4 as uuidv4 } from "uuid";
export default function TodoList() {
const [todos, setTodos] = useState([]);
const [category, setCategory] = useState("Work"); // Work, Life, Want
const [text, setText] = useState("");
const [editText, seteditText] = useState("");
const newTodo = {
id: uuidv4(),
text,
isDone: false,
isEdit: false,
category,
};
//추가하기
const addTodo = () => {
setTodos((prev) => [...prev, newTodo]); //newTodo를 추가 하기 위해
setText("");
};
//완료하기
const setDone = (id) => {
// 1. id를 매개변수로 받는다.
// 2. id에 해당하는 배열의 요소를 찾는다.
// 3. 그 배열의 요소의 isDone 값을 토글링한 후에 setTodos.
const newTodos = [...todos];
const idx = newTodos.findIndex((todo) => todo.id === id);
newTodos[idx].isDone = !newTodos[idx].isDone;
setTodos(newTodos);
};
//삭제하기
const removeTodo = (id) => {
Alert.alert("삭제", "정말 삭제 하시겠습니까?", [
{
text: "취소",
style: "cancle",
onPress: () => console.log("취소클릭"),
},
{
text: "삭제",
style: "destructive",
onPress: () => {
const newTodos = todos.filter((todo) => todo.id !== id);
setTodos(newTodos);
},
},
]);
};
//수정하기
const Edit = (id) => {
const newTodos = [...todos];
const idx = newTodos.findIndex((todo) => todo.id === id);
newTodos[idx].isEdit = !newTodos[idx].isEdit;
setTodos(newTodos);
};
const editTodo = (id) => {
// 1. id 값을 받아서 해당 배열 요소 찾음
// 2. todos[idx].text = editText로 바꿔줌
const newTodos = [...todos];
const idx = newTodos.findIndex((todo) => todo.id === id);
newTodos[idx].text = editText;
newTodos[idx].isEdit = false;
setTodos(newTodos);
seteditText("");
};
return (
<SafeAreaView style={styles.safearea}>
<View style={styles.container}>
<View style={styles.imageview}>
<Image
source={require("../assets/todolistlogo.png")}
style={styles.logoimage}
/>
</View>
<View style={styles.tabs}>
<TouchableOpacity
onPress={() => {
setCategory("Work");
}}
style={{
...styles.tab,
backgroundColor: category === "Work" ? "black" : "#868e96",
}}
>
<Text style={styles.tabText}>Work</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() => setCategory("Life")}
style={{
...styles.tab,
backgroundColor: category === "Life" ? "black" : "#868e96",
}}
>
<Text style={styles.tabText}>Life</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() => setCategory("Want")}
style={{
...styles.tab,
backgroundColor: category === "Want" ? "black" : "#868e96",
}}
>
<Text style={styles.tabText}>Want</Text>
</TouchableOpacity>
</View>
<View style={styles.inputWrapper}>
<TextInput
onSubmitEditing={addTodo}
onChangeText={setText}
value={text}
placeholder="Please write it here."
style={styles.input}
/>
</View>
<ScrollView>
{todos.map((todo) => {
if (category === todo.category) {
return (
<View key={todo.id} style={styles.task}>
{todo.isEdit ? (
<TextInput
onSubmitEditing={() => {
editTodo(todo.id);
}}
onChangeText={seteditText}
value={editText}
style={{ flex: 0.9, backgroundColor: "#e9ecefd" }}
/>
) : (
<Text
style={{
textDecorationLine: todo.isDone
? "line-through"
: "none",
}}
>
{todo.text}
</Text>
)}
<View style={{ flexDirection: "row" }}>
<TouchableOpacity onPress={() => setDone(todo.id)}>
<MaterialCommunityIcons
name={
todo.isDone
? "tooltip-check"
: "tooltip-check-outline"
}
size={24}
color="black"
/>
</TouchableOpacity>
<TouchableOpacity
onPress={() => {
Edit(todo.id);
}}
>
<MaterialCommunityIcons
style={{
marginLeft: 10,
}}
name={
todo.isEdit ? "comment-edit" : "comment-edit-outline"
}
size={24}
color="black"
/>
</TouchableOpacity>
<TouchableOpacity
onPress={() => {
removeTodo(todo.id);
}}
>
<MaterialCommunityIcons
style={{ marginLeft: 10 }}
name="delete-outline"
size={24}
color="black"
/>
</TouchableOpacity>
</View>
</View>
);
}
})}
</ScrollView>
</View>
<StatusBar
barStyle="dark-content"
backgroundColor={"transparent"}
translucent={false}
/>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
safearea: {
flex: 1,
},
container: {
flex: 1,
paddingVertical: 30,
paddingHorizontal: 20,
backgroundColor: "white",
},
imageview: {
flexDirection: "row",
},
logoimage: {
alignItems: "center",
marginLeft: "auto",
marginRight: "auto",
},
tabs: {
flexDirection: "row",
justifyContent: "space-between",
},
tab: {
backgroundColor: "white",
paddingHorizontal: 10,
paddingVertical: 15,
width: "30%",
alignItems: "center",
borderRadius: 30,
},
tabText: {
fontWeight: "600",
fontSize: 18,
color: "white",
},
inputWrapper: {
borderTopWidth: 1,
borderBottomWidth: 1,
paddingVertical: 15,
marginTop: 15,
marginBottom: 15,
},
input: {
borderWidth: 1,
paddingVertical: 10,
paddingHorizontal: 20,
},
task: {
flexDirection: "row",
paddingVertical: 10,
paddingHorizontal: 10,
alignItems: "center",
justifyContent: "space-between",
marginBottom: 10,
borderColor: "black",
borderWidth: 2,
},
});
App.js의 코드 전체 부분이다.
수정기능과 똑같이 카테고리를 구분하는 것 또한 비슷한 코드를 사용한다.
완성 된 TodoList의 모습이다.
사실 강의를 보며 만들었는데 혼자서 하기에는 이해가 더 필요한 것 같다.
다음은 마이페이지를 완료하고 firebase에 연결하는 것 까지 마무리를 해보자.
반응형