let's get IT with DAVINA 💻

React로 TodoApp 만들기 (3)Delete,Update 기능 개발 본문

DEV_IN/React

React로 TodoApp 만들기 (3)Delete,Update 기능 개발

다빈치코드💎 2023. 3. 2. 23:51

1. 먼저, 해당 글을 누르면 ⊕버튼 눌렀을 때 뜨는 창이 나오게 해야겠지?!

  • TodoItem.js
    • 특정 글을 누르니까 여기서({text}있는 부분=글을 눌렀을때) onClick함수 추가해줘!
import React from "react";
import { MdCheckBox, MdCheckBoxOutlineBlank } from "react-icons/md";
import "./TodoItem.css";

const TodoItem = ({
    todo,
    onCheckToggle,
    onInsertToggle,
    onChangeSelectedTodo,
}) => {
    const { id, text, checked } = todo;
    return (
        <div className='TodoItem'>
            <div className={`content ${checked ? "checked" : ""}`}>
                {checked ? (
                    <MdCheckBox
                        onClick={() => {
                            onCheckToggle(id);
                        }}
                    />
                ) : (
                    <MdCheckBoxOutlineBlank
                        onClick={() => {
                            onCheckToggle(id);
                        }}
                    />
                )}
                <div
                    className='text'
                    onClick={() => { //3. ❗️ 이 부분 추가!!
                        onChangeSelectedTodo(todo); //그러면 사용자가 선택한 글이 setSelectedTodo의 값이 돼!
                        onInsertToggle();
                    }}
                >
                    {text}
                </div>
            </div>
        </div>
    );
};

export default TodoItem;
  • App.js
import React, { useState } from "react";
import { MdAddCircle } from "react-icons/md";
import "./App.css";
import Template from "./components/Template";
import TodoInsert from "./components/TodoInsert";
import TodoList from "./components/TodoList";

let nextId = 4;

const App = () => {
    const [selectedTodo, setSelectedTodo] = useState(null); //1. ❗️이 부분 추가
    const [insertToggle, setInsertToggle] = useState(false);

    const [todos, setTodos] = useState([
        {
            id: 1,
            text: "할일 1",
            checked: true,
        },
        {
            id: 2,
            text: "할일 2",
            checked: false,
        },
        {
            id: 3,
            text: "할일 3",
            checked: true,
        },
    ]);

    const onInsertToggle = () => {
        if (selectedTodo) {
            setSelectedTodo(null);
        }
        setInsertToggle((prev) => !prev);
    };

    const onInsertTodo = (text) => {
        if (text === "") {
            return alert("할 일을 입력해주세요.");
        } else {
            const todo = {
                id: nextId,
                text,
                checked: false,
            };
            setTodos((todos) => todos.concat(todo)); //상태 불변성 유지 push 대신 concat
            nextId++;
        }
    };

    const onCheckToggle = (id) => {
        setTodos((todos) =>
            todos.map((todo) =>
                todo.id === id ? { ...todo, checked: !todo.checked } : todo
            )
        );
    };

    const onChangeSelectedTodo = (todo) => { //2. ❗️이 부분 추가
        setSelectedTodo(todo);
    };

    const onRemove = (id) => {
        onInsertToggle();
        setTodos((todos) => todos.filter((todo) => todo.id !== id));
    };

    const onUpdate = (id, text) => {
        onInsertToggle();
        setTodos((todos) =>
            todos.map((todo) => (todo.id === id ? { ...todo, text } : todo))
        );
    };

    return (
        <Template todoLength={todos.length}>
            <TodoList
                todos={todos}
                onCheckToggle={onCheckToggle}
                onInsertToggle={onInsertToggle}
                onChangeSelectedTodo={onChangeSelectedTodo}
            />
            <div className='add-todo-button' onClick={onInsertToggle}>
                <MdAddCircle />
            </div>
            {insertToggle && (
                <TodoInsert
                    selectedTodo={selectedTodo}
                    onInsertToggle={onInsertToggle}
                    onInsertTodo={onInsertTodo}
                    onRemove={onRemove}
                    onUpdate={onUpdate}
                />
            )}
        </Template>
    );
};

export default App;

2. ⊕추가 모달창과 수정용 모달창은 다르게 해야겠지?

- 새롭게 추가하는게 아닌, 기존 글을 띄운 상태로 그걸 수정하도록..

  • TodoInsert.js
import React, { useEffect, useState } from "react";
import { MdAddCircle } from "react-icons/md";
import { TiTrash, TiPencil } from "react-icons/ti";
import "./TodoInsert.css";

const TodoInsert = ({
    onInsertToggle,
    onInsertTodo,
    selectedTodo,
    onRemove,
    onUpdate,
}) => {
    const [value, setValue] = useState("");

    const onChange = (e) => {
        setValue(e.target.value);
    };

    const onSubmit = (e) => {
        e.preventDefault();
        onInsertTodo(value);
        setValue("");
        onInsertToggle();
    };

    useEffect(() => { //❗️ 1. 이 부분 추가! 받아온(선택된) todo의 text값으로 value값 바꿔주라
        if (selectedTodo) {
            setValue(selectedTodo.text);
        }
    }, [selectedTodo]);

    return (
        <div>
            <div className='background' onClick={onInsertToggle}></div>
            <form
                onSubmit={
                    selectedTodo
                        ? () => {
                              onUpdate(selectedTodo.id, value); //❗️ 4. 선택한 글의 id와 변경된 value로 update함수에 넣어주기
                          }
                        : onSubmit
                }
            >
                <input
                    placeholder='add your to-do'
                    value={value}
                    onChange={onChange}
                ></input>
                {selectedTodo ? ( //❗️ 2. selectedTodo가 있으면 수정용 모달창
                    <div className='rewrite'>
                        <TiPencil
                            onClick={() => {
                                onUpdate(selectedTodo.id, value); //❗️ 5. 선택한 글의 id와 변경된 value로 update함수에 넣어주기
                            }}
                        />
                        <TiTrash onClick={() => onRemove(selectedTodo.id)} />
                    </div>
                ) : ( //❗️ 3. selectedTodo가 없으면 추가용 모달창
                    <button type='submit'>
                        <MdAddCircle />
                    </button>
                )}
            </form>
        </div>
    );
};

export default TodoInsert;
  • App.js
    • 수정용 함수와 제거용 함수 만들기
    const onInsertToggle = () => {
        if (selectedTodo) {
            setSelectedTodo(null);
        }
        setInsertToggle((prev) => !prev);
    };

	const onRemove = (id) => {
        onInsertToggle();
        setTodos((todos) => todos.filter((todo) => todo.id !== id));
    };

    const onUpdate = (id, text) => {
        onInsertToggle();
        setTodos((todos) =>
            todos.map((todo) => (todo.id === id ? { ...todo, text } : todo))
        );
    };
    
    return (
    ...생략
🚫 여기서!! onInsertToggle에 
if (selectedTodo) { setSelectedTodo(null); }를 추가해주는 이유!?

특정 글을 눌러 수정을 하다 말고, ⊕버튼으로 글 추가할 때 모달창에 수정용 모달창이 그대로 남아있기때문에!
selectedTodo가 있을 경우에는 setSelectedTodo를 null값으로 변경해 초기화시키고
아닌 경우, InsertToggle이 그대로 true/false값 변경되어서 창 열고닫기 해주기!
Tadan 쨔쟌 완성본

'DEV_IN > React' 카테고리의 다른 글

React Query  (2) 2023.03.24
React로 TodoApp 만들기 (2)Create 기능 개발  (2) 2023.03.02
React로 TodoApp 만들기 (1)Setup  (4) 2023.03.02
JSX  (2) 2023.02.21
What is React?  (3) 2023.02.21
Comments