본문 바로가기
프로젝트/회고

react를 활용한 todo list - 개인 과제 프로젝트

by dev__log 2024. 1. 23.

📢 프로젝트 소개

 

✏️ 프로젝트 설명

react props와 useState를 활용하여 나만의 todo list 구현

 

💻 프로젝트 구현 기능

  • todo list 항목 추가/삭제 기능
    • 추가의 경우 빈칸으로 입력하는지 유효성 검사
  • todo list 항목 완료/취소 기능
  • todo의 상태가 true 일 경우 취소버튼, false 일 경우 완료 버튼으로 조건부 렌더링
  • todo 항목에 맞는 리스트에 분리하여 노출
  • 공통으로 사용할 수 있는 부분은 컴포넌트로 분리
  • 완료된 todo의 경우 디자인 조금 어둡게 처리

 

🔥 배운 점 / 느낀 점

제일 어려웠던 부분은 완료/취소 기능이었다. 처음에는 완료/취소를 Item 컴포넌트에서 하려고 했었다. Item 컴포넌트는 List 컴포넌트에 import 해서 List의 자식 컴포넌트로 있었는데, List에서 props로 내려주는데 Item 컴포넌트에서 각자의 useState를 변경하니 List에는 전혀 반영되지 않았다. 이걸 어떻게 해결해야 할지에 대해서 제일 시간이 오래 걸렸다.

 

완료하면 완료 리스트로 이동해야 하는데, Item 컴포넌트에서 각자의 useState를 가지고 있으니 List 컴포넌트에서는 반영이 되지 않았던 것이다. (취소도 마찬가지)

 

그래서 완료/취소 기능을 List 컴포넌트에서 함수를 props에 담아서 전달하는 방식으로 했다. props에 담을 함수의 리턴문에 함수를 넣어서 보냈다.

 

onClick의 event.target을 가져와서 그 타깃의 조상 요소에서 id 값을 가지고 있는 input hidden을 찾아 id 값을 가져왔다. 그리고 현재 데이터와 id 가 같은 데이터를 변수에 담고 상태를 변경한 후 useState를 업데이트했다.

 

아래 completeItem과 cancelItem, deleteItem 코드를 참고

import React, { useState } from 'react';
import Item from './Item';

export default function List({data}) {
  const [currData, setCurrData] = useState(data);
  
  //완료 데이터
  const completeData = data.filter((el) => {
    return el.isDone === true;
  });

  //미완료 데이터
  const incompleteData = data.filter((el) => {
    return el.isDone === false;
  });

  //완료 기능 - 함수를 만들어서 전달
  const completeItem = () => {
    //data 에서 해당 id 찾아서 값 변경
    return function(e){ //함수를 props로 전달하기 위해 리턴문에 함수를 만들었다.
      const parent = e.target.parentElement.parentElement; //event target 의 조상 요소를 찾는다
      const id = parent.querySelector('.target-id').value; //찾은 조상 요소의 자식중에 id 값을 가지고 있는 input 의 value 를 가져온다.
      
      let findData = data.find((el) => { //현재 데이터와 같은 id를 가진 데이터를 가져온다.
        return el.id === Number(id); //id 가 string 으로 가져와져서 number로 형변환.
      });
      findData.isDone = true; //상태를 완료로 변경한다.
      setCurrData([findData]); //업데이트를 해준다.
    }
  }

  //취소 기능
  const cancelItem = () => {
    //data 에서 해당 id 찾아서 값 변경
    return function(e){
      const parent = e.target.parentElement.parentElement;
      const id = parent.querySelector('.target-id').value;
      
      let findData = data.find((el) => {
        return el.id === Number(id);
      });
      findData.isDone = false;
      setCurrData([findData]);
      console.log(findData);
    }
  }

  //삭제 기능
  const deleteItem = () => {
    return function(e){
      const parent = e.target.parentElement.parentElement;
      const id = parent.querySelector('.target-id').value;
      console.log(data)
      let findIdx = data.findIndex((el) => { //삭제할 아이템의 index를 구하고
        return el.id === Number(id);
      });
      let newData = data.splice(findIdx,1); //splice로 삭제한다.
      setCurrData(newData); //업데이트를 해준다.
    }
  }

  return (
    <>
      <h2 className='page-title'>🔥 Working</h2>
      <ul className='todo-list'>
        {
          incompleteData.map((el) => {
            return <Item id={el.id} title={el.title} contents={el.contents} isDone={el.isDone} key={el.id} completeItem={completeItem()} deleteItem={deleteItem()} />
          })
        }
      </ul>
      <h2 className='page-title'>🎉 Done</h2>
      <ul className='todo-list'>
      {
        completeData.map((el) => {
          return <Item id={el.id} title={el.title} contents={el.contents} isDone={el.isDone} key={el.id} cancelItem={cancelItem()} deleteItem={deleteItem()} />
        })
      }
      </ul>
    </>
  );
}

 

제일 어려웠던 부분인데 이렇게 함수에서 함수를 리턴하고 이런 방식은 처음 적용해 보았다...

완성해서 기쁘다 정말로...

하지만 수정해야 하는 부분이 많이 남았다.

 

❕ 아쉬운 점

마감 기한에 쫓겨서 제출하는데 급급했다. 그래서 퀄리티가 너무 아쉽다. 

코드도 기능 구현에 치중하다 보니 정리가 많이 필요할 것 같다. 

 

첫 리액트 프로젝트였는데, 이론만 보다가 직접 props, useState로 구현하려고 하니 너무 어려웠다. 

어려운 만큼 배운 것도 많았고, 좀 더 강의 복습을 해서 내 거로 만들어야 활용을 더 할 수 있을 것 같다는 생각이 든다.

 

그리고 오늘 코드 리뷰를 받았다.

  • 시맨틱 태그 사용하기
  • 삭제 시 정말 삭제하는지 확인하고 삭제 진행하기
  • App.js로 jsx로 변경하기
    -> 적용 완료
  • App.js 에 Header 컴포넌트와 AddTodo 컴포넌트만 불러오고 List 컴포넌트는 여기서 안 불러오는데 리스트는 없는 것 같다는 느낌을 받는다고 했다. 이 부분도 더 컴포넌트 어떻게 할지 고민하기
  • document.querySelector 등 react에서 document로 직접 접근하지 말기
  • 고유한 id 값은 crypto.randomUUID 또는 shortid 적용해 보기
    -> crypto.randomUUID 적용 완료 확인
  • working list와 done list 도 공통 컴포넌트로 만들기
  • item에서 props를 지금 여러 개 받고 있는데 정말 필요한 부분인지 확인하기

위와 같은 사항을 받았다. 조금씩 개선해 나가야 할 것 같다.

UX도 더 신경 쓰자