Diary/Retrospective

[항해99 / TIL] 🚢 23-04-17 리액트 useState로 투두리스트 만들기

Olivia Kim 2023. 4. 17. 21:31
반응형

 

요구사항 정의

예시 화면

 

구현해야 할 기능

  • UI 구현하기
  • Todo 추가하기
  • Todo 삭제하기
  • Todo 완료 상태 변경하기 (완료 ↔ 진행 중)

 

 

요구사항

  • 디자인은 자유이나 화면 구성은 동일하게 진행
  • 제목과 내용을 입력하고, 추가하기 버튼 클릭 시 Working에 새로운 Todo 추가
  • 추가 완료되면 제목, 내용 input 빈 값으로 바뀌도록 구성
  • Todo의 isDone 상태가 true면 상태 버튼의 라벨을 취소, 상태가 false면 버튼의 라벨을 완료로 조건부 렌더링
  • Todo의 상태가 Working이면 위쪽에 위치, Done이면 아래쪽에 위치
  • Layout 최대 넓이는 1200px, 최소 넓이는 800px로 제한하고, 전체 화면의 가운데로 정렬
  • 컴포넌트 구조는 자유롭게 구현하고 분리한 컴포넌트는 README에 작성

 

 

 


컴포넌트 분리 구조

구현 및 실행 화면

 

최초 작성

📦src
 ┣ 📂components
 ┃ ┣ 📜Form.jsx
 ┃ ┣ 📜Header.jsx
 ┃ ┣ 📜List.jsx
 ┃ ┗ 📜ListMap.jsx
 ┣ 📜App.css
 ┣ 📜App.jsx
 ┣ 📜index.js
 ┗ 📜reportWebVitals.js

 

화면의 큰 레이아웃을 기준으로 Header, inpnut을 입력받는 Form, 내용을 띄우는 영역인 List로 나누고 List 내에서 중복되는 함수를 별도의 컴포넌트로 분리했다.

 

 

리팩토링 후

📦src
 ┣ 📂components
 ┃ ┣ 📜Form.jsx
 ┃ ┣ 📜Header.jsx
 ┃ ┣ 📜ListWorking.jsx
 ┃ ┣ 📜ListDone.jsx
 ┃ ┗ 📜ListMap.jsx
 ┣ 📜App.css
 ┣ 📜App.jsx
 ┣ 📜index.js
 ┗ 📜reportWebVitals.js

 

List 부분을 Working과 Done 컴포넌트로 나눠주었다.

 

 

 


중점을 둔 사항

1. 시맨틱 태그 사용

// Form.jsx

...
<section className="form">
  <form className="form__area">
    <label htmlFor="form__title">
      <strong>제목</strong>
      <input 
        type="text"
        id="form__title"
        value={title}
        onChange={onTitleChange}
      />
    </label>
    <label htmlFor="form__body">
      <strong>내용</strong>
      <input
        type="text"
        id="form__body"
        value={body}
        onChange={onBodyChange}
      />
    </label>
    <button
      className="form__button"
      onClick={onSubmitClick}
    >
      <strong>추가하기</strong>
    </button>
  </form>
</section>
...

 

이전 글 트러블슈팅에서도 적었듯 모든 웹 사용자가 동일한 환경에서 웹에 접근하지 않고, 검색 엔진 로봇 등을 고려해서 HTML 코드는 최대한 시맨틱 태그를 지키려고 노력한다. 이번 과제에서도 큰 영역들을 <section>으로 나누고 <label>안에 <input>을 넣으며 적절한 태그를 사용하려 했다. 어차피 버튼 영역인데 버튼 내에 <strong> 처리를 한건 아쉽지만 그 부분만 따로 CSS를 작성하기도 애매해서 어차피 쓸 거면 시맨틱 태그를 쓰자는 생각으로 <b> 태그보다는 <strong>을 적용했다.

 

 

2. 변수명은 알아보기 쉽게 작성

드림코딩 엘리님(💓)의 강의에서 배운 좋은 습관들이 몇 개 있다. 그중 하나는 변수를 알아보기 쉽게 작성하는 것! 그냥 title이 아니라 form_title처럼 변수 명으로도 어떤 역할을 하는지 알 수 있도록 고려해서 작성했다.

 

 

3. 컴포넌트 분리

'리액트는 SPA 기반이다, useState를 쓴다' 라는 부분까지만 예습을 하고 시작한 리액트 주차. 강의를 들을 때는 컴포넌트 나누는 거 어렵지 않은데? 라고 생각했는데 막상 과제에서 직접 컴포넌트를 나누려니 막막했다.

 

 

맨 처음 컴포넌트를 나눌 때는 화면에서 보여지는 레이아웃을 기반으로 나눴다. Header, Form, List. 하지만 기능적으로 나눴다기보다 그냥 구역별로 나눴다는 의미가 커서 어떻게 해야 진짜 의미 있게 컴포넌트를 나눌 수 있을지 고민했다.

 

 

문득 엊그제 chatGPT에게 리액트를 물어보며 정리했던 내용이 생각났다. 리액트에서 상태가 변경되면 Virtual DOM에 그게 반영되어서 브라우저의 DOM과 비교해 '변경된' node만 반영한다! 그렇다면 리렌더링 될 부분을 기준으로 컴포넌트를 나눠보자고 생각했다.

 

 

또한 기술매니저님께서 컴포넌트 분리와 관련해 다음과 같은 조언을 주셨다. '완료' 버튼만 기준으로 봤을 때 완료값이 변경되면 working에서는 해당 내용이 빠져야 하고 done에는 해당 내용이 추가되어야 한다. 따라서 두 영역 모두 리렌더링 되므로 하나로 합쳐도 된다. 그런데 '삭제' 버튼까지 포함해서 보면 working에 있는 값이 삭제된다고 done까지 리렌더링이 될 필요는 없다. (삭제된 노드에 대해서는 리렌더링이 일어나지 않기 때문이다.) 따라서 두 개를 모두 고려한다면 working, done으로 나누는 것이 좋아 보인다.

 

 

리렌더링이 될 부분을 기준으로 나눠보자까지는 생각했는데 아직 그 데이터가 useState를 통해 어느 영역을 리렌더링 시킬지까지는 생각하지 못했는데 기술 매니저님이 잘 정리해 주셔서 데이터의 흐름을 따라가야 한다는 포인트를 짚을 수 있었다! 

 

 

 


트러블슈팅

 

맨 처음 구현할 때 id에 length + 1 값을 부여했는데 id가 중복되는 현상이 발생했다. 리액트 공식 문서를 읽으며 해답을 찾았고 해당 트러블 슈팅은 깃허브 리드미(▼)에 작성해 두었다.

 

 

 

https://github.com/hansololiviakim/react-assignment/tree/main/beginner/3_to-do-list

 

GitHub - hansololiviakim/react-assignment: 항해99 14기 리액트주차 실습

항해99 14기 리액트주차 실습. Contribute to hansololiviakim/react-assignment development by creating an account on GitHub.

github.com

 

 

 


질의사항

시니어 코치님과의 질의

(오늘 마침 주에 딱 한 번 있는 시니어 코치님과의 질의 시간이라 컴포넌트 관련한 질문을 드릴 수 있었다!)

❓ 지금은 컴포넌트를 나눌 때 리렌더링이 될 것 같은 기준으로 나눠보는 연습을 하고 있다. 찾아보니 컴포넌트를 분리하는 디자인 패턴이 따로 있는데 디자인 패턴 적용하는 법을 연습하는게 좋은지 궁금하다.

 

💡 디자인 패턴은 많은 사람들이 고민한 결과물이다. 그걸 먼저 보게 되면 문제를 풀다가 정답을 먼저 보는 것과 비슷하다. 지금 리렌더링을 고려해서 컴포넌트 나누는 연습을 하는 건 아주 좋은 방식이다. 계속 컴포넌트를 나누는 연습을 하다 보면 본인만의 컴포넌트를 나누는 방식이 생길 것이고, 그 방식과 비슷한 디자인 패턴 또한 찾을 수 있을 것이다.

 

 

 

기술매니저님과의 질의

❓ 변수명을 HTML 부분은 스네이크 케이스, JavaScript 부분은 카멜 케이스로 표기하였는데 하나로 통일하는 게 더 좋은지, 어느 표기법을 더 권장하는지 궁금하다.

 

💡 보통은 HTML에 케밥 케이스를 많이 사용한다. JS는 사용한 대로 카멜 케이스를 사용하면 된다.

 

 

❓ 컴포넌트를 나눌 때 CSS 파일도 컴포넌트에 맞춰 나눠야 하는지 궁금하다. 만약 나눈다면, 폴더 어느 곳에 위치하는지 알고 싶다.

 

💡 다음 주차 강의를 들은 이후로는 CSS 파일을 사용하지 않을 것이다. 컴포넌트 별로 Styled Components 또는 Tailwind 등을 사용하게 될 것이다.

 

 

❓ 이번 과제를 하며 컴포넌트를 분리하는 게 손에 익지 않아 App.jsx에 모든 코드를 작성해 구현하고 이후 컴포넌트를 분리해 보는 식으로 작성하였다. 손에 익게 되면 컴포넌트를 바로 나누면서 개발이 가능한지, 그리고 지금은 이 방법도 괜찮은지 궁금하다.

 

💡 처음에 구현할 때는 지금 방법을 사용하면서 공부하는 것이 편할 것이다. 어차피 숙달되면 바로 컴포넌트를 나누고 개발을 진행하게 된다.

 

 

❓ 지금은 삭제한 내용에 대해 filter를 걸었는데 데이터 양이 아주 많았을 경우에도 불변성을 지키기 위해 원본 배열에 직접적으로 삭제를 하지 않는 형식으로 진행되는지, 실무에서도 덮어 씌우는 방식으로 값을 변경하는지 궁금하다. 더 좋은 방법이 있다면 알고 싶다.

 

💡 리액트에서 데이터를 다룰 때는 원본 배열을 직접 삭제하는 일이 거의 없다. 지금처럼 filter를 사용하면 되고 실무에서 데이터 양이 아주 많아질 경우에는 처음부터 백엔드에서 쪼개서 주는 데이터를 받게 된다.

 

 

 


 

✅ 이전에는 프로그래머란 사람의 요구사항과 그걸 대신해내는 컴퓨터 사이를 연결하는 통·번역가라고 생각했다. 하지만 공부를 거듭할수록 사용자가 원하는 데이터와 컴퓨터로 추출할 수 있는 데이터를 어떻게 가공하고 효율적으로 보여줄 것인지를 고민하는 역할이라는 생각이 든다. 특히나 컴포넌트를 나눌 때도 결국 데이터가 어떻게 흐르고, 어떻게 반영되냐에 따라 리렌더링 여부가 결정되기 때문에 데이터를 기반으로 한 사고력을 키워가야겠다고 다짐했다.

 


 

 

 

반응형