요구사항 정의
구현해야 할 기능
- 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
질의사항
시니어 코치님과의 질의
(오늘 마침 주에 딱 한 번 있는 시니어 코치님과의 질의 시간이라 컴포넌트 관련한 질문을 드릴 수 있었다!)
❓ 지금은 컴포넌트를 나눌 때 리렌더링이 될 것 같은 기준으로 나눠보는 연습을 하고 있다. 찾아보니 컴포넌트를 분리하는 디자인 패턴이 따로 있는데 디자인 패턴 적용하는 법을 연습하는게 좋은지 궁금하다.
💡 디자인 패턴은 많은 사람들이 고민한 결과물이다. 그걸 먼저 보게 되면 문제를 풀다가 정답을 먼저 보는 것과 비슷하다. 지금 리렌더링을 고려해서 컴포넌트 나누는 연습을 하는 건 아주 좋은 방식이다. 계속 컴포넌트를 나누는 연습을 하다 보면 본인만의 컴포넌트를 나누는 방식이 생길 것이고, 그 방식과 비슷한 디자인 패턴 또한 찾을 수 있을 것이다.
기술매니저님과의 질의
❓ 변수명을 HTML 부분은 스네이크 케이스, JavaScript 부분은 카멜 케이스로 표기하였는데 하나로 통일하는 게 더 좋은지, 어느 표기법을 더 권장하는지 궁금하다.
💡 보통은 HTML에 케밥 케이스를 많이 사용한다. JS는 사용한 대로 카멜 케이스를 사용하면 된다.
❓ 컴포넌트를 나눌 때 CSS 파일도 컴포넌트에 맞춰 나눠야 하는지 궁금하다. 만약 나눈다면, 폴더 어느 곳에 위치하는지 알고 싶다.
💡 다음 주차 강의를 들은 이후로는 CSS 파일을 사용하지 않을 것이다. 컴포넌트 별로 Styled Components 또는 Tailwind 등을 사용하게 될 것이다.
❓ 이번 과제를 하며 컴포넌트를 분리하는 게 손에 익지 않아 App.jsx에 모든 코드를 작성해 구현하고 이후 컴포넌트를 분리해 보는 식으로 작성하였다. 손에 익게 되면 컴포넌트를 바로 나누면서 개발이 가능한지, 그리고 지금은 이 방법도 괜찮은지 궁금하다.
💡 처음에 구현할 때는 지금 방법을 사용하면서 공부하는 것이 편할 것이다. 어차피 숙달되면 바로 컴포넌트를 나누고 개발을 진행하게 된다.
❓ 지금은 삭제한 내용에 대해 filter를 걸었는데 데이터 양이 아주 많았을 경우에도 불변성을 지키기 위해 원본 배열에 직접적으로 삭제를 하지 않는 형식으로 진행되는지, 실무에서도 덮어 씌우는 방식으로 값을 변경하는지 궁금하다. 더 좋은 방법이 있다면 알고 싶다.
💡 리액트에서 데이터를 다룰 때는 원본 배열을 직접 삭제하는 일이 거의 없다. 지금처럼 filter를 사용하면 되고 실무에서 데이터 양이 아주 많아질 경우에는 처음부터 백엔드에서 쪼개서 주는 데이터를 받게 된다.
✅ 이전에는 프로그래머란 사람의 요구사항과 그걸 대신해내는 컴퓨터 사이를 연결하는 통·번역가라고 생각했다. 하지만 공부를 거듭할수록 사용자가 원하는 데이터와 컴퓨터로 추출할 수 있는 데이터를 어떻게 가공하고 효율적으로 보여줄 것인지를 고민하는 역할이라는 생각이 든다. 특히나 컴포넌트를 나눌 때도 결국 데이터가 어떻게 흐르고, 어떻게 반영되냐에 따라 리렌더링 여부가 결정되기 때문에 데이터를 기반으로 한 사고력을 키워가야겠다고 다짐했다.
'Diary > Retrospective' 카테고리의 다른 글
[항해99 / TIL] 🚢 23-05-03 리액트 query, axios로 게시판 만들기 (4) | 2023.05.03 |
---|---|
[항해99 / TIL] 🚢 23-04-29 Styled Components로 화면 요소 만들기 (0) | 2023.04.29 |
[항해99 / TIL] 🚢 23-04-19 리액트 Redux로 투두리스트 만들기 (0) | 2023.04.19 |
[항해99 / TIL] 🚢 23-04-15 chatGPT에게 리액트 기초 물어보기 (2) | 2023.04.16 |
[항해99 / 온보딩주차] 🔎 풀스택 미니 프로젝트 회고 (0) | 2023.04.06 |