[TIL]231106_React로 Todo List 만들기

ㅇㅖㅈㅣ·2023년 11월 6일
3

Today I Learned

목록 보기
19/93
post-thumbnail

👩🏻‍💻 Today Learn

  • 개인과제 Todo List 완성 및 제출
  • isDone을 활용한 완료, 취소 버튼 구현
  • React 컴포넌트 분리

🤦🏻‍♀️ 고민한 내용

완료한 부분

  • Todo List의 전체적인 레이아웃 및 기본적인 css
  • input에 값을 입력하면 카드가 생성
  • 삭제하기 버튼 클릭시 카드 삭제


막힌 부분

문제 1) input에 빈 값을 입력하면 내용을 입력하라는 alert창을 띄웠는데 빈 카드가 붙어버림..

문제 2) 카드의 isDone이 false이면 working에 위치, true이면 clear에 위치하게 만들기

문제 3) 문제의 컴포넌트 분리..................

막혔던 부분을 (추리고 추려서) 큼직한 것 3가지만 정리해보려고 한다.


문제 1) 고민 및 해결

// 등록하기 버튼
  // 버튼에는 이미 클릭이벤트가 있기 때문에 굳이 안넣어도됨! -> form의 onSubmit에 한번에 가능
  // const addBtn = () => {
  // };
const onSubmit = (e) => {
    // form태그를 사용하면 자동으로 새로고침 현상이 발생함 -> preventDefault() 로 해당이벤트의 기본동작을 실행하지 않도록 해줘야함
    // 가장 상단에 위치해야 새로고침 현상을 방지할 수 있음.... 중간에 넣었다가 alert창 나오고 다 사라지는
    e.preventDefault();

    // 빈값일때 내용을 입력하라는 alert창 띄우기
    // 근데 왜 카드가 붙지.....? addBtn이 실행된 후에 alert창이 띄워지는 순서였기 때문이었음!!!! 순서중요!!!
    if (title === "") {
      alert("제목을 입력해주세요");
      return;
    }
    if (text === "") {
      alert("내용을 입력해주세요");
      return;
    }

    const setTodo = {
      id: Date.now(),
      title: title,
      text: text,
      isDone: false,
    };
    setList([...list, setTodo]);
    // 등록하기 버튼 누르면 input값 초기화시키기
    setText("");
    setTitle("");
  };

주석처리한 부분이 덕지덕지 이긴 하지만 고민한 흔적을 남기기위해 함께 넣어보았다!

해결과정은 생각보다 간단했는데 카드를 등록하는 코드가 상단에 있고 alert창을 띄우는 코드가 아래에 있었기 때문에 카드가 붙은 후에 alert창이 등장했던 것이다....

아직 전문용어에 대한 지식이 부족한 상태라 거창한 설명은 어렵지만 코드를 작성할 때는 실행해야하는 과정을 순서대로 구상해서 작업해야한다!
컴퓨터가 아무리 똑똑하다고 하지만 순서가 꼬여버리면 온전히 실행해줄리가 없다는 것이다...
(그 와중에 수정하다가 e.preventDefault(); 를 if 아래에 넣었다가 alert창이 뜨고나면 붙어있던 카드가 다 사라져버리기도 했던....ㅎ..)


문제 2) 고민 및 해결

이 부분은 사실 주말에도 작업하면서 몇시간동안 머리를 쥐어 뜯었던거 같다.

접근방식

// isDone이 false인 것만 필터링
  const workingTodo = list.filter((list) => {
    return !list.isDone;
  });

  // isDone이 true인 것만 필터링
  const clearTodo = list.filter((list) => {
    return list.isDone;
  });

우선 처음 투두리스트 카드를 등록하면 isDone이 false로 설정했다.
그래서 false상태면 working으로 true상태면 clear로 필터링 시키는 함수를 만들었다.
filter() 함수 사용

 {/* Working이 그려지는 부분 */}
      <div className="List_container">
        <h1 className="List_title">👩🏻‍💻 Working 🧑🏻‍💻</h1>
        <div className="List_box">
          {workingTodo.map((item) => {
            return (
              <TodoCard
                key={item.id}
                item={item}
                list={list}
                setList={setList}
                clearTodo={clearTodo}
              />
            );
          })}
        </div>
      </div>

      {/* Clear가 그려지는 부분 */}
      <div className="List_container">
        <h1 className="List_title">🙆🏻‍♀️ Clear 🙆🏻‍♂️</h1>
        <div className="List_box">
          {clearTodo.map((item) => {
            return (
              <TodoCard
                key={item.id}
                item={item}
                list={list}
                setList={setList}
                clearTodo={clearTodo}
              />
            );
          })}
        </div>
      </div>

map() 함수를 사용하여 각 위치에 맞게 필터링한 요소들을 새로운 배열로 만들어 붙였다.

그리고 추가로 해당 위치에 따라 버튼에 그려지는 텍스트가 '완료하기', '취소하기'로 다르게 설정하는 코드까지 넣어야 마무리가 가능하다.

const OnToggle = ({ item, list, setList, text }) => {
  // 완료하기 - 취소하기
  const clearCancelBtn = (id) => {
    setList((prev) => {
      return prev.map((list) => {
        return list.id === id ? { ...list, isDone: !list.isDone } : list;
      });
    });
  };

  return (
    <button className="Toggle_button" onClick={() => clearCancelBtn(item.id)}>
      {text}
    </button>
  );
};

OnToggle 컴포넌트안에 clearCancelBtn 함수를 만들어 넣은 후 버튼을 그려줬다.

</button>
          <OnToggle
            setList={setList}
            item={item}
            list={list}
            text={item.isDone ? "취소하기" : "완료하기"}
          />
        </div>

이렇게 머리를 한움큼 쥐어뜯은 후에 구현은 완성했다.


문제 3) 고민 및 해결

지금까지 한 작업은 맨처음 생성된 App.js에 하나의 컴포넌트로 작업했었기 때문에 반복되는 부분을 분리하는 과정이 필요했다.

TodoAdd / TodoCard / OnToggle 이렇게 세개로 분리하여 props 를 이용하여 컴포넌트간에 정보를 전달해주었다.

💡 props란?

쉽게말해 컴포넌트 끼리의 정보교환 방식!

  • 부모 ➡️ 자식방향인 단방향으로만 흐른다. (위에서 아래방향)
  • 읽기 전용이기 때문에 변경하지 않는다.
// TodoAdd 에서 보내준 내용
return (
              <TodoCard
                key={item.id}
                item={item}
                list={list}
                setList={setList}
                clearTodo={clearTodo}
              />
            );

// TodoCard 에서 받은 내용
const TodoCard = ({ item, list, setList, clearTodo }) => {}

파일을 분리하기 위해서 필수적으로 들어가야 하는 내용

// 내보내는 파일
export default TodoCard;
// 받는 파일
import TodoCard from "./component/TodoCard";

이 원리를 머리로 완전히 이해하지 못한 상태로 컴포넌트를 분리하다보니 TodoAdd에서 TodoCard컴포넌트까지는 큰 문제가 없었는데 OnToggle로 내려줄때 대환장파티가 발생했었다.

그렇지만 꾸역꾸역 해내고야 말았다!!(feat.도움의 손길..)


✍🏻 회고

하나하나의 단계를 만들어 가기 위해 자료도 계속 찾아보고 구글링도 해보고.. 이렇게 저렇게 바꿔보면서 다양하게 시도해보았지만 내가 작성하고 있는 코드에 적용하는것이 쉽지 않았었다.

아직은 문제가 발생했을때 여기저기 물어보면서 조언을 구하는것이 더 많지만 그냥 '해결해주세요!'가 아닌 이유와 분석에 대해 이해하려고 노력했고 그러다보니 코드가 조금씩 눈에 읽히는것 같아서 신기하기도했다. 그리고 무엇보다 원하는 화면이 그려지고 작동했을 때는 정말.... 뿌듯했ㄷㅏ..🥹
이러한 성취감을 앞으로도 계속 느끼고싶다.
(결국 또 일기가 되어버린 회고)

profile
웰씽킹_나는 경쟁력을 갖춘 FE개발자로 성장할 것이다.

2개의 댓글

comment-user-thumbnail
2023년 11월 7일

멋있어요

1개의 답글