[TIL] 05.17 :: Todo List 리팩토링

yeseul·2024년 5월 20일

<TIL>

목록 보기
16/43

개인과제 제출 후, 튜터님들의 피드백을 바탕으로 코드 리팩토링을 진행했다.
변경 사항은 아래와 같다.

  • 사이트 피드백
  1. 폴더구조 나누기
  2. Styled Component
  3. 페이지 reload 없애기
  4. PlanList 중복 호출 부분

  • 코드리뷰를 통해 받은 피드백
  1. 변수명 수정
  2. 라이브러리 버전 신규로 변경
  3. 느슨한 비교 -> 엄격한 비교
  4. App 컴포넌트(최상단)에서 props 로 굳이 안내려줘도 되는 것들에대해 props 수정


✔️구조 수정

* 컴포넌트 분리 기준

  • 재사용성
    사진과 같이 이번 과제에서는 TodoList 구역이 2개이며, todo 는 굉장히 자주 반복된다. 우선 나는 나열되는 묶음끼리 컴포넌트화 시키는게 쉬워서 저런식으로 분리시켰다.

  • 복잡성
    기능이 복잡할수록, 계층적 구조를 활용하는게 좋다.
    상위 컴포넌트에서 데이터와 로직을 관리하고, 하위 컴포넌트에서 UI 렌더링을 담당하는 식으로 구조화할 수 있다.

* CSS와 .jsx 는 한 폴더에!

리액트로 처음 프로젝트를 진행하다보니 컴포넌트를 분리할때 혹시나 import, export 로 오류가 생길까봐 첫 제출때는 하나의 src 폴더 안에 모든 파일이 구분없이 들어가있었다. 폴더 구조에 대해서는 무엇을 기준으로 나누는게 좋을지 모르겠어서 튜터님께 여쭤보았다.

새롭게 알게된 사실은 프로젝트가 커질수록 jsx(기능을 담고있는 부분) 뿐만아니라 css 파일(디자인)의 수도 커지게 되므로, 컴포넌트에서 import 하는 css도 함께 폴더에 넣는것을 지향해야한다고 하셨다. 바닐라 자바스크립트로 프로젝트를 했을때는 style 폴더에 css 다 넣고, module 끼리 모아서 구분시킨거랑은 다른 방향이라 새로웠지만 설명을 들어보니 이해가 잘 되더라..!! css 파일 수백개면.. 거기서 어떻게든 찾기는 하겠다만 생각만해도 막막하다...🥹

* Styled Component

앞서 폴더 구조를 변경하면서 css 파일에 대한 이야기가 나왔었는데, 위와 같은 방식으로 하다보면 결국 폴더의 수도 많아지게 된다. 이로인해 현재 많이쓰이는 방법으로는 스타일드 컴포넌트가 있다.

  • 스타일드 컴포넌트(Styled Components)는 리액트에서 CSS-in-JS 방식으로 스타일을 관리할 수 있게 해주는 라이브러리다. 이를 통해 컴포넌트 단위로 스타일을 캡슐화하고 재사용할 수 있으며, jsx 파일안에 스타일도 작성하게되므로 파일안에 코드가 길어지지만, 관리하기 쉽다.

    큰 특징으로는, 아래 두개가 있다.
    • 프로퍼티 활용: 프로퍼티를 사용하여 동적으로 스타일을 변경할 수 있다.
    • 상속: 기존 스타일을 상속받아 새로운 스타일을 만들 수 있다.

jsx에서 인라인으로 스타일을 적용해봤을때 하나의 파일안에 코드가 길어지는게 불편했었는데, 이 방법은 다음 개인과제때 구현해볼수있으니 그땐 또 느낌이 어떨지 궁금하다.


✔️코드 수정

* SPA의 장점을 잃는 reload

나는 보통 웹페이지를 이용할때 메인제목(h1)이나 로고를 눌러서 메인으로 돌아가곤 한다. 그 경험을 바탕으로 지금까지의 과제에서 여러페이지가 생기더라도 메인으로 돌아가게 해놨었는데, 그 중 한 방법이window.location.reload() 였다. reload를 하면 현재 접속중인 웹페이지를 다시불러와 새로고침을 할 수 있다.

이번에도 h1 에 새로고침을 적용했는데, 리액트는 single page 이므로 새로고침을 지양하는게 좋다고 하셨다.
이유를 알아보니, 페이지 전체를 reload하면 전체 화면을 새로 내려받아야 하므로 빠른 페이지 전환이 불가능해진다. 또한 전체 페이지를 다시 렌더링하게 되므로 '화면 깜빡임'이 발생하고 성능이 저하될수있다.
그럼 언제 사용하는지 여쭤보니, 거~~의 안쓰신다고 한다..!!! 페이지 이동의 경우 리액트 라우터를 통해 할 수있으므로 그 부분에 대한 공부를 해보면 쉽게 이해가 될 것 같다.

* 변수명은 확실하고 직관적으로, 단수/복수 구분까지!

  • const (todo, setTodos) -> todo 를 썼으면 setTodo 로 맞춰써 쓰는게 덜 헷갈린다. 단수를 썼으면 단수로 맞추고, 복수로 썼으면 복수로 맞추자!
    ex) 변수명 plans 이면 setplans 로. / completeHandler -> 토글핸들러라는 이름이 더 명확하다.
  • 프로젝트 내에서 일관되게 사용하기.
  • 혹시라도 변수명 한번에 다 바꿀일 생긴다면
    1.바꾸려는 단어 선택
    2.단축키 입력 : Ctrl+Shift+L
    3.단어 수정하면 동시에 수정됨

* 라이브러리는 최신버전으로 사용하자.

  • 유효성검사할때 alert 창은 너무 안이뻐서 부트캠프 첫 과제때부터 swal을 즐겨쓰곤하는데, 그동안 라이브러리 버전을 항상 2로 써왔다가 이번엔 무슨정신인지.. 그냥 1 버전을 사용했었다.(코드리뷰 전까지 어느 버전인지도 잊고있었음 ㅜ)
    SweetAlert2 는 무려 엊그제도 새로 업데이트 했더라...
    라이브러리 사용할때는 혹시 모르니, 공식 사이트 가서 새로운 버전 확인 후 사용하기!

  • uuid는 v4를 가장 많이 씀!
    UUID에는 총 5가지 버전이 있으며, 각 버전마다 고유한 특성과 사용 목적이 있다.

    • Version 1 (v1): 시간 기반 UUID
    • Version 2 (v2): 도메인 기반 UUID
    • Version 3 (v3): 이름 기반 UUID (MD5 해시)
    • Version 4 (v4): 무작위 UUID
    • Version 5 (v5): 이름 기반 UUID (SHA-1 해시)
      이 중 가장 널리 사용되는 버전은 v4 UUID.
      v4 UUID는 완전히 무작위로 생성되므로 고유성이 보장되어 일반적인 용도로 사용된다.

* 상태는 어떤 컴포넌트가 관리하는 것이 좋은가?

  • 최상위 컴포넌트보다는 가급적 중간단계(?)의 컨테이너 컴포넌트가 관리하는 것을 권장
    • (부모 컴포넌트 렌더링 → 자식 컴포넌트 렌더링)
  • 상태(or 상태변경함수) 공유의 수단으로 props 사용
    • (props는 부모에서 자식 방향으로만)
  • 최하위 컴포넌트(ex. 아이템 컴포넌트)는 상태를 갖지 않는 것이 좋다.
    • (props로 화면을 나타내는 역할만 한다.)

재제출하면서 InputForm.jsx와 App.jsx 의 props 구조를 바꿨다.
처음 제출한 코드에는 App에 모든 부담을 다 줬었다.
예를들어, plan 을 생성할때 input 받아야하는 title과 content 의 상태까지 다 App에서 관리하여 TodoList, Todo에 전부 props로 내려줬어야 했다.

💭 title, content 모두 props 로 '공유' 가 필요한 상황인가? 라는 물음을 가져야 한다.

-> 나는 어쨌든 main 화면을 담당하는 App 에서 데이터의 이동이 이뤄지므로 App에서 상태를 다 관리해야 된다고 생각했는데, 튜터님께서 이부분을 정확하게 짚어주셨다.
❗input 에서 추가하기 버튼을 누르고 form을 제출하면, title과 body 는 이미 저장된 값이다.
❗쉽게 생각하면 title, body = 재료, plan 칸 = 제품 이다.

상태관리와 props 에 대해 요약하자면 아래와 같다.

  • 부모 컴포넌트에 모든 책임을 다 주려고 하면 안된다.
  • 가급적이면 자식에서 다룰 수 있는건 귀속시키자.
  • 최상위 컴포넌트일수록 단순하게 만들어야함. 맨 밑도 단순하게. 중간이 복잡하게.
  • form 에서 title, body 갖고있어도 됨. 직접 관리해도 문제없다.
  • 자식이 리렌더링 된다고 해서 부모도 리렌더링 되지않는다.
  • 부모가 렌더링 되면 자식도 렌더링 된다.
  • 컴포넌트 유형 분류
    • Container 컴포넌트:
      - 보통 상위 컴포넌트로, 애플리케이션의 상태 관리와 로직을 담당.
      - 데이터 가져오기, 상태 관리, 이벤트 핸들링 등의 역할을 한다.
      - 프레젠테이션 컴포넌트에 데이터와 함수를 전달하는 역할.
    • Presentation 컴포넌트 :
      - 상태 없이 props를 받아 화면에 표시하는 역할을 한다.
      - UI 요소와 스타일링을 담당하며, 비즈니스 로직은 포함하지 않는다.
      - 재사용성이 높고 테스트하기 쉽다.
    • Wrapper 컴포넌트 :
      - 레이아웃 관점에서 다른 컴포넌트를 감싸는 역할을 한다.
      - 상태 관리나 비즈니스 로직은 포함하지 않고, 주로 스타일링과 구조화에 집중.

💡일부만 다르고 나머지 코드가(기능이) 비슷하다면 컴포넌트로 만들수있다.
리팩토링 할때 틀린그림찾기하듯이 화면분할 해놓고 비교해가며 분리시켜보자.


* 함수형 업데이트

새로운 plan을 생성할때 오류가 나는 부분이어서 고민하다가 팀원분께 여쭤보니 함수형 업데이트에 대해 알려주셨다.

setPlans([...plans, newPlan]); 와

setPlans((plans) => [...plans, newPlan]);의 차이를 알아보자.


  • setPlans([...plans, newPlan]);
    이 방식은 직접적으로 plans 상태를 업데이트하는 것이다.
    이 경우, React는 plans 상태가 변경되었다는 것을 인식하지만, 이전 상태 값을 참조할 수 없다. 따라서 이 방식은 상태 업데이트 시 이전 상태 값을 활용할 수 없다.

  • setPlans((plans) => [...plans, newPlan]);
    이 방식은 함수형 업데이트를 사용한다.
    함수형 업데이트를 사용하면 이전 상태 값을 참조할 수 있으며, 이전 상태 값을 활용하여 새로운 상태 값을 생성할 수 있다.

-> InputForm 에 props로 setPlans는 받아오지만, plans는 받아오지 않아서 이런 현상이 발생했었다.
화살표 함수가 정상적으로 동작하는 이유는 setPlans((prevPlan)=> [...prevPlan, newPlan]) 이런식으로 set해주는 함수에서 전의 plan 값을 받아온 다음에 써주기 때문이다.
💡내가 실수한 코드는 아무것도 받지 않은 상태에서 set 해주려고 해서 에러가 났던것이다!

-> setPlans([...plans, newPlan]) 의 경우, onSubmit({setplans, plans}) 를 받아오고 넘겨줄때도
InputForm에 plans = {plans} 도 추가로 내려주면 작동하긴함.
그치만 화살표함수써서 콜백으로 리턴하는게 최대한 자식을 안내려주므로 함수형 업데이트 사용이 좋다.


* 회고

이번 과제는 useState 와 props, 컴포넌트 분리에 대해 자세히 알고 넘어갈 수 있어서 많이 배울 수 있었다. 확실히 처음 코드짤땐 생소했어도 수정에 수정을 할수록 더 이해가 된다.

지난번 팀프로젝트때 Date.now() 를 써봤어서 시간말고 또 새로운 키 값이 뭐가 좋을지 알아보다가 과제제출 전 리팩토링때 uuid를 써봤다. 이 점을 코드리뷰때 칭찬해주셔서 정말 기분이 좋았다! 리팩토링 할때마다 다 된 기능에 혹시나 오류생겨서 제출할때 영향 미칠까봐 조심스럽게 더 알아보고 하는 편인데, 그러다보니 이론부분 말고 새로운 내용도 프로젝트에 접목시킬 수 있었다. 덕분에 프로젝트 하나가 끝날때마다 많이 배우고있다. 특히 이번 과제는 리액트 입문주차로서 굉장히 생소했지만 은근 리액트 사용틀?이 심플해서 재밌게 진행했다.

다만 힘들었던 점은, css 부분에 시간을 얼마나 투자할지 고민이 많았다.
예를들어 Plan 의 제목이나 내용이 엄청 길어질경우에 대해 테스트를 해보다가, 오버된 내용이 div 를 넘어서서 옆칸까지 침범하곤 했는데 도~저히 그 상태로 과제 제출을 하기가 싫더라..ㅜ
그래서 어쩌다보니 Plan item 안에 스크롤을 만들었고, 내 취향대로 스타일도 나름 줘가면서 하니 더 재밌었던거 같다. 이렇게 제출 후에 피드백을 보면 css 에 신경쓰는 시간을 줄이고 컴포넌트 분리나 props, 기능부분에 대해 더 시간을 투자해야되나 싶기도 하지만.., 외적인? 부분이 거슬리게 보이는건 계속 신경쓰이는걸 어쩌겠나 싶다. ㅎ
마지막에 스타일 적용할 생각으로 힘내서 기능구현하는 거일지도.... 😶‍🌫️

ㅎㅎ 귀여운 스크롤과 Plan !!

🎈타임어택 준비하면서 오랜만에 손코딩을 했는데 학교다닐때 시험공부하던 생각도 나고..! 키보드 말고 손으로 작성하니 훨씬 잘 기억난다. 앞으로도 자주 손으로 직접 코드를 써봐야겠음!

🤓이번주 리액트 숙련주차도 화이팅해보자!!

0개의 댓글