(5) Todo List 기본 기능 CRUD 추가 - 2 (갱신)

2023. 6. 8. 14:28Github 프로젝트/todolist반응형웹앱

728x90
반응형
SMALL

지난시간 CRUD의 읽기, 쓰기의 대해서 다뤄봤습니다.

(4) Todo List 기본 기능 CRUD 추가 - 1 (읽기, 쓰기) : https://berkley.tistory.com/8

 

(4) Todo List 기본 기능 CRUD 추가 - 1 (읽기, 쓰기)

지난 시간 반응형 웹&앱 UI 작성편을 이어서 기능 추가를 진행하였습니다. 이 글을 보기 전, 아래의 링크를 먼저 수행 하신 후 다음 단계로 넘어가시면 되겠습니다. (3) 반응형 Todolist UI 작업 진행

berkley.tistory.com

 

 

이번 시간에는 갱신의 대해서 다뤄보겠습니다.

 

 

1. Todo List CRUD 중 갱신 

기존의 state 변수 todoList에 필드 "title, contents" 만 설정 되어있다.

여기서 file에 isTitleUpdate 에 boolean 타입의 객체를 활용해 줍니다. (샘플로 이용시)

  useEffect(() => {
    setTodoList([
      {
        title: "Redux 학습하기",
        contents: [
          "로그인/로그아웃 가능 여부 확인",
          "localstorage/sessionstorage 학습",
        ],
        isTitleUpdate:false,
      },
      {
        title: "SpringBoot 학습하기",
        contents: ["Spring Security 구현", "Spring MVC 패턴 익히기"],
        isTitleUpdate:false,
      },
      {
        title: "JWT 인증 처리",
        contents: ["JWT 개념 익히기"],
        isTitleUpdate:false,
      },
    ]);
  }, []);

 

※ 이전에 사용했던 생성부분에 isTitleUpdate 객체도 추가해줍니다. (생성 후 갱신기능 사용시 반드시 수정해줄것)

  /**
   * 입력시 Todolist 추가하는 기능
   */
  const createTitleButton = () => {
    let to = [];
    to.push(...todoList);
    to.push({
      title: createInputTitle?.title,
      contents: [],
      isTitleUpdate:false,
    });
    setTodoList(to);
  };

 

 

 

다음으로는 수정 모드 진입 시 Input 모드로 변환해주고 onChange용 state문이랑 메서드를 작성해줍니다.

TodoList에서는 state값이 배열로 지정되기 때문에 배열별로 각각 저장해줘야 합니다.

  // Todolist title 수정용 state 
  const [changeTitle, setChangeTitle] = useState();
  // 수정용 onChange
  const updateTitlOnChange = (e,index) => {
    const { name, value } = e.target;
    setChangeTitle({[index]:{[name]:value}});
    console.log(changeTitle);
  }

 

 

이후, 현재 읽기 전용으로 수정된 map안에 수정모드를 반영 시킵니다.

 

<수정전>

{
  // 다음은 각각 데이터를 불려올 때 map을 주로 사용합니다.
  // todoList에 저장된 state 값을
  // 유사 forEach문처럼 todo를 이용하여 출력하고,
  // 상위 div에 key값을 설정하기 위해 index 값을 집어 넣어야 합니다.
  todoList?.map((todo, index) => (
    <div key={index} className="todoContainer">
    {/* 이부분 수정 전 시작*/}
      <div className="todoTitle">
        {todo?.title} <PlusCircle />
      </div>
    {/* 이부분 수정 전 끝*/}

      {todo?.contents?.map((tc, tcIndex) => (
        <div key={tcIndex} className="todoContents">
          - {tc} <Trash3 />
        </div>
      ))}
    </div>
  ))
}

 

<수정 후>

{
  // 다음은 각각 데이터를 불려올 때 map을 주로 사용합니다.
  // todoList에 저장된 state 값을
  // 유사 forEach문처럼 todo를 이용하여 출력하고,
  // 상위 div에 key값을 설정하기 위해 index 값을 집어 넣어야 합니다.
  todoList?.map((todo, index) => (
    <div key={index} className="todoContainer">
      <div className="todoTitle">
      {/* 수정 후 시작*/}
        {isTitleUpdate ? (
          <Input name="title" defaultValue={todo?.title} onChange={(e) => updateTitlOnChange(e,index)} />
          <Button>todolist수정</Button>
          <Button onClick={() => setIsTitleUpdate(!isTitleUpdate)}>취소</Button>
        ) : (
          <div>
            {todo?.title}
            <Button onClick={() => setIsTitleUpdate(!isTitleUpdate)}>수정</Button> <PlusCircle />
          </div>
        )}
      {/* 수정 후 끝*/}
      </div>

      {todo?.contents?.map((tc, tcIndex) => (
        <div key={tcIndex} className="todoContents">
          - {tc} <Trash3 />
        </div>
      ))}
    </div>
  ))
}

 

여기서부터는 1200px 기준으로 결과물을 도출하겠습니다.

현재는 퍼블리셔 영역이 아닌 프론트엔드 React 개발자로써 진행을 하는 것이니 UI부분은 차후 진행을 할 것입니다.

이에 참고하며, 디자인 부분은 차후에 진행하도록 하겠습니다.

이에 따른 아래와 같이 결과물은 다음과 같습니다.

차후, 수정 버튼 누르면 전체 수정 모드로 진행 됩니다. 

차후, 분리 작업을 통해 해당 부분 수정 클릭 시 해당부분만 수정하도록 Refactoring 하면서 진행 하도록 하겠습니다.

 

<갱신 작업 전>

 

<갱신 작업 후>

==> console.log 로 확인하시면, 입력값이 변환하는 것을 확인 할 수 있습니다.

 

 

 

 

 

다음은 입력 후 갱신 확정하는 기능을 수행하겠습니다.

 

먼저, 사전 작업으로 npm 패키지에서 immutability-helper 설치하겠습니다.

powershell을 열고 npm install immutability-helper --save 로 이용하여 설치하겠습니다.

 

아래와 같이 설치가 끝난 이후 모습 

 

 

 

설치가 끝난 후 본론으로 들어와 아래와 같이 import 해줍니다.

import update from "immutability-helper";

 

이후, 아래와 같이 불변성을 유지하면서 update() 메서드를 활용하여 filed : { $set : value } 기능으로 state값으로 변경해줍니다.

  // 입력 후 갱신 메서드
  const updateTitle = (index) => {
    setTodoList(
      update(todoList, {
        [index]: {
          title: { $set: changeTitle[index].title },
        },
      })
    );
  };

 

렌더링 부분을 수정 을 합니다.

          <div className="todo">
            {
              // 다음은 각각 데이터를 불려올 때 map을 주로 사용합니다.
              // todoList에 저장된 state 값을
              // 유사 forEach문처럼 todo를 이용하여 출력하고,
              // 상위 div에 key값을 설정하기 위해 index 값을 집어 넣어야 합니다.
              todoList?.map((todo, index) => (
                <div key={index} className="todoContainer">
                  <div className="todoTitle">
                    {isTitleUpdate ? (
                      <div>
                        <Input
                          name="title"
                          defaultValue={todo?.title}
                          onChange={(e) => updateTitlOnChange(e, index)}
                        />
                        /* 이부분 수정 시작 */
                        <Button onClick={() => updateTitle(index)}>
                          todolist수정
                        </Button>
                        /* 이부분 수정 끝 */
                        <Button
                          onClick={() => setIsTitleUpdate(!isTitleUpdate)}
                        >
                          취소
                        </Button>
                      </div>
                    ) : (
                      <div>
                        {todo?.title}
                        <Button
                          onClick={() => setIsTitleUpdate(!isTitleUpdate)}
                        >
                          수정
                        </Button>{" "}
                        <PlusCircle />
                      </div>
                    )}
                  </div>

                  {todo?.contents?.map((tc, tcIndex) => (
                    <div key={tcIndex} className="todoContents">
                      - {tc} <Trash3 />
                    </div>
                  ))}
                </div>
              ))
            }
          </div>

 

다음과 같이 업데이트를 수행해봅니다.

 

 

(1) 메인 화면

 

 

 (2) 수정 모드 돌입

 

 

(3) 입력 후 수정

 

(4) 돌아가기 (취소 버튼)

 

 

2. 완성된 코드

import {
  Button,
  ButtonGroup,
  Card,
  CardBody,
  CardHeader,
  CardTitle,
  Form,
  Input,
} from "reactstrap";
import "./App.css";
import { PlusCircle, Trash3 } from "react-bootstrap-icons";
import { useEffect, useState } from "react";
import update from "immutability-helper";

function App() {
  /**
   * 필요 key:value값
   * title, contents
   * 이 값은
   */
  const [todoList, setTodoList] = useState([]);
  const [createInputTitle, setCreateInputTitle] = useState();

  useEffect(() => {
    setTodoList([
      {
        title: "Redux 학습하기",
        contents: [
          "로그인/로그아웃 가능 여부 확인",
          "localstorage/sessionstorage 학습",
        ],
      },
      {
        title: "SpringBoot 학습하기",
        contents: ["Spring Security 구현", "Spring MVC 패턴 익히기"],
      },
      {
        title: "JWT 인증 처리",
        contents: ["JWT 개념 익히기"],
      },
    ]);
  }, []);

  /**
   * 다음은 TodoList 입력용 이벤트 함수
   */
  const createTitleOnchange = (e) => {
    const { name, value } = e.target;
    setCreateInputTitle({
      ...createInputTitle,
      [name]: value,
    });
  };
  /**
   * 입력시 Todolist 추가하는 기능
   */
  const createTitleButton = () => {
    let to = [];
    to.push(...todoList);
    to.push({
      title: createInputTitle?.title,
      contents: [],
    });
    setTodoList(to);
  };

  // 갱신모드 설정
  const [isTitleUpdate, setIsTitleUpdate] = useState(false);
  
  // Todolist title 수정용 state
  const [changeTitle, setChangeTitle] = useState();
  const updateTitlOnChange = (e, index) => {
    const { name, value } = e.target;
    setChangeTitle({ [index]: { [name]: value } });
    console.log(changeTitle);
  };

  // 입력 후 갱신 메서드
  const updateTitle = (index) => {
    setTodoList(
      update(todoList, {
        [index]: {
          title: { $set: changeTitle[index].title },
        },
      })
    );
  };

  return (
    <div className="my-2 background-container">
      <Card className="my-2 container">
        <CardHeader className="header-container">
          To-do list 반응형 웹 개발
        </CardHeader>
        <CardBody>
          <CardTitle tag="h2">To-do list</CardTitle>
          <div className="todo">
            {
              // 다음은 각각 데이터를 불려올 때 map을 주로 사용합니다.
              // todoList에 저장된 state 값을
              // 유사 forEach문처럼 todo를 이용하여 출력하고,
              // 상위 div에 key값을 설정하기 위해 index 값을 집어 넣어야 합니다.
              todoList?.map((todo, index) => (
                <div key={index} className="todoContainer">
                  <div className="todoTitle">
                    {isTitleUpdate ? (
                      <div>
                        <Input
                          name="title"
                          defaultValue={todo?.title}
                          onChange={(e) => updateTitlOnChange(e, index)}
                        />
                        <Button onClick={() => updateTitle(index)}>
                          todolist수정
                        </Button>
                        <Button
                          onClick={() => setIsTitleUpdate(!isTitleUpdate)}
                        >
                          취소
                        </Button>
                      </div>
                    ) : (
                      <div>
                        {todo?.title}
                        <Button
                          onClick={() => setIsTitleUpdate(!isTitleUpdate)}
                        >
                          수정
                        </Button>{" "}
                        <PlusCircle />
                      </div>
                    )}
                  </div>

                  {todo?.contents?.map((tc, tcIndex) => (
                    <div key={tcIndex} className="todoContents">
                      - {tc} <Trash3 />
                    </div>
                  ))}
                </div>
              ))
            }
          </div>

          {/**
           *
           */}
          <Form className="addGroup">
            <Input
              className="addInput"
              name="title"
              defaultValue={createInputTitle}
              onChange={createTitleOnchange}
            />
            <Button className="addButton" onClick={createTitleButton}>
              추가
            </Button>
          </Form>
        </CardBody>
      </Card>
    </div>
  );
}

 

 

 

다음 시간에는 삭제 버튼 기능을 구현해보겠습니다.

 

(6) TodoList CRUD 삭제 : https://berkley.tistory.com/10

 

(6) Todo List 기본 기능 CRUD 추가 - 3 (삭제)

지난시간에는 갱신의 대해서 다뤄봤습니다. 갱신 부터 진행 후 다음은 삭제에 대해 다루겠습니다. (5) Todo List 기본 기능 CRUD 추가 - 2 (갱신) : https://berkley.tistory.com/9 (5) Todo List 기본 기능 CRUD 추가

berkley.tistory.com

 

 

 

 

 

728x90
반응형
LIST