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에 연결하는 것 까지 마무리를 해보자.

반응형