[TIL] React로 To Do List 만들기

·2023년 11월 3일
1

TIL

목록 보기
23/85
post-thumbnail

[React로 My To Do List 만들기!]

  • 구현해야 할 기능
    • Todo 추가하기
    • Todo 삭제하기
    • Todo 완료상태 변경하기 (완료 <-> 진행중)
  • 요구사항
    • 제목과 내용을 입력하고 추가하기 버튼 클릭하면 Working에 새로운 Todo가 추가되고 제목, 내용 input은 빈 값으로 바뀐다.
    • Todo의 isDone 상태가 true이면, 버튼의 라벨을 취소, isDone 상태가 false 이면 버튼의 라벨을 완료로 조건부 렌더링 한다.
    • Todo의 상태가 working이면 위쪽에 위치하고, done이면 아래쪽에 위치하도록 구현한다.
    • Layout의 최대 넓이는 1200px, 최소 넓이는 800px로 제한하고 전체 화면의 가운데로 정렬한다.

vanilla javascript로 to-do list를 구현했다면 다소 복잡하게 코드가 작성되었을 텐데, (추가할 때 todo 를 그려주고, 삭제할 때는 해당하는 li 태그를 찾아 remove 하고.. ) 리액트를 사용하니 todos 라는array에 [{id: 0, title: “”, body: “”, isDone: false}] 와 같은 객체를 넣어서 관리하니 , toDos가 바뀔 때마다 (setTodos가 실행될 때마다) 리렌더링 되어서 더 쉽게 구현할 수 있었던 것 같다.

UI 구현 😄

오늘 오전 9시에 개인 과제가 주어졌는데, 기능적인 부분은 사실 오전에 다 완성했다!
(깜찍한 디자인으로 완성하고 싶었으나 나의 미적 감각으로는 저게 맥시멈이지 않을까..)
일단 App.jsx에 돌아가도록 다 작성하고, 이후에 컴포넌트를 분리했는데 분리하는 과정에서 약간의 오류가 생겨서 그걸 하나씩 해결해 나가는 재미도 있었다.

자주 보는 Warning

warning은 error와 달라서 무시해도 작동은 하지만, 매우 거슬린다. 훗날 문제가 될 지도 모르니 고쳐보자.🛠️

input의 value가 undefined일 때

Warning: A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component.
경고: 구성 요소가 제어되지 않는 입력을 제어하도록 변경하고 있습니다. 이는 값이 정의되지 않은 값에서 정의된 값으로 변경되어 발생할 수 있으므로 발생하지 않아야 합니다. 구성 요소의 수명 동안 제어 또는 제어되지 않은 입력 요소를 사용할 것인지 결정합니다.

이 warning은 input 의 value가 처음에 undefined일 때 주로 발생한다.
input의 value는 title이라는 state와 연결되어 있다.
그리고 onChange 이벤트가 발생할 때마다 setTitle을 통해 title을 변경하여 value로 지정한다.

warning 코드 ⚠️

const [title, setTitle] = useState(); // 초기값 없음
<input
  value={title} // value를 title로 지정
  onChange={(e) => setTitle(e.target.value)}
  id="title"
  type="text"
  placeholder="Write your to do title"
  required
  maxLength={20}
/>

해결방법 1️⃣

input의 value를 || (or)연산자로 title이 undefined일 때 공백("")으로 지정한다.

const [title, setTitle] = useState();
<input
  value={title || ""} // 이렇게
  onChange={(e) => setTitle(e.target.value)}
  id="title"
  type="text"
  placeholder="Write your to do title"
  required
  maxLength={20}
/>

해결방법 2️⃣

useState()를 사용할 때 초기값을 공백("")으로 지정해준다.

const [title, setTitle] = useState(""); // 이렇게
<input
  value={title} 
  onChange={(e) => setTitle(e.target.value)}
  id="title"
  type="text"
  placeholder="Write your to do title"
  required
  maxLength={20}
/>

map을 통해 rendering 되는 component에 unique한 key값을 주지 않았을 때

Warning: Each child in a list should have a unique "key" prop.
목록의 각 자식은 고유한 "키" 를 가져야 한다.

이 warning은 map 메서드를 활용하여 여러 요소를 반복적으로 생성할 때 주로 발생한다.
여기서는 Todo라는 컴포넌트를 map 메서드를 통해 반복적으로 생성하고 있는데, 반복적으로 생성되는 요소에 unique한 key값을 주어야 이 warning이 사라지게 된다.

warning 코드 ⚠️

<ul className="todo-list">
    {todos
     .filter((todo) => todo.isDone === false)
       .map((todo) => (
         <Todo todo={todo} todos={todos} setTodos={setTodos}>
         완료
         </Todo>
      ))}
</ul>

해결방법

<ul className="todo-list">
    {todos
     .filter((todo) => todo.isDone === false)
       .map((todo) => (
         <Todo key={todo.id} todo={todo} todos={todos} setTodos={setTodos}> // 여기서 Key 지정
         완료
         </Todo>
      ))}
</ul>

(훗날 위 코드는 TodoList라는 컴포넌트를 분리하게 되면서 변경됩니다..ㅎ)

완성

👉 https://todo-list-theta-ebon.vercel.app/

느낀 점

컴포넌트를 분리하여 관리하니 레고 조립하는 것 같기도 하고 뚝딱뚝딱 만들어가는 재미가 있다.
state가 바뀔 때마다 rerendering되는 게 정말 편한 것 같다. (리액트의 파워💪)

튜터님 리뷰

profile
느리더라도 조금씩, 꾸준히

0개의 댓글