Yuyeol 님의 상세페이지[8팀 정유열] Chapter 1-3. 프레임워크 없이 SPA 만들기

과제 체크포인트

배포 링크

https://yuyeol.github.io/front_6th_chapter1-3/

기본과제

equalities

  • shallowEquals 구현 완료
  • deepEquals 구현 완료

hooks

  • useRef 구현 완료
  • useMemo 구현 완료
  • useCallback 구현 완료
  • useDeepMemo 구현 완료
  • useShallowState 구현 완료
  • useAutoCallback 구현 완료

High Order Components

  • memo 구현 완료
  • deepMemo 구현 완료

심화 과제

hooks

  • createObserver를 useSyncExternalStore에 사용하기 적합한 코드로 개선
  • useShallowSelector 구현
  • useStore 구현
  • useRouter 구현
  • useStorage 구현

context

  • ToastContext, ModalContext 개선

과제 셀프회고

기술적 성장과 학습효과

useShallowState를 구현하면서 새로 안 사실

setState로 prev와 동일한 값을 넣으면 기본적으로 리렌더가 발생하지 않음을 알게되었습니다. 이 사실을 알기 전에는 useShallowState가 왜 필요한 것인지 처음에는 이해하지 못했었고, 상태가 참조값인 경우 prev의 주소가 항상 변하는 특징으로 인해 동일한 값을 초기화해도 리렌더링을 발생시키기 때문에 이 훅이 필요하다는 것을 알게 되었습니다.

store / storage / router 코드 구현 과정 중의 고민

createObserver → useShallowSelector → useStore 유기적 연결을 파악하는데 어려움이 있었습니다. 단순히 구현하라고 지시한 모듈을 하나씩만 구현해보려니 막막한 부분이 많았고 제시해주신 학습 자료들과 학습을 통해 어떤 구조로 어떻게 연결할지 찾아보면서 기존 라이브러리들의 코드들을 답습하여 답안에 가까운 코드를 작성하는 방법을 배웠습니다.

ToastContext 리팩토링을 통한 상태관리에 대한 고찰

컨텍스트의 렌더링 문제를 해결하면서 프롭스 드릴링과 Context API, 상태관리 라이브러리의 리렌더 특징에 대해 다시 복습하는 기회를 가졌고, 문서로 남길 수 있었습니다.

자랑하고 싶은 코드

어느정도 정답이나 구현 디테일이 균일할 수밖에 없는 과제인 것 같아서 크게 자랑할 것은 없는것 같습니다. 비슷한 로직을 사용한다면, 통일성을 지키며 코드를 작성했고 알아보기 쉽고 복집하지 않게 코드를 작성하기 위해 노력했습니다. 아래 예시 코드와 비슷한 수준으로 전체적으로 일관성을 신경쓰며 작성했습니다.

  • 명확한 분기 분리
  • early return과 선택적 에러처리
  • 가독성 보강이나 재사용이 필요할 때 선택적으로 변수 선언
type AnonymousObj = { [key: string]: unknown };

export const shallowEquals = (a: unknown, b: unknown): boolean => {
  if (typeof a !== typeof b) return false;

  if (a === null || b === null) return a === b;

  if (Array.isArray(a) && Array.isArray(b)) {
    if (a.length !== b.length) return false;
    return a.every((item, index) => item === b[index]);
  }

  if (typeof a === "object" && typeof b === "object") {
    const aKeys = Object.keys(a);
    const bKeys = Object.keys(b);
    if (aKeys.length !== bKeys.length) return false;
    return aKeys.every((key) => (a as AnonymousObj)[key] === (b as AnonymousObj)[key]);
  }

  return a === b;
};

개선이 필요하다고 생각하는 코드

ToastContext의 컨텍스트를 분리하는 방향으로 리팩토링을 진행하고 좀 더 리렌더 성능을 향상 시켜보면 어떨까 하고 상태관리 라이브러리들에서 흔히 사용되는 셀렉터 구현을 고려해보았습니다. 하지만 변경이 잦은 상태를 소비하는 컴포넌트는 단 하나였고, 샐렉터를 사용하지 않아도 성능적인 차이가 없어서 지금 프로덕트 단계에서는 필요없는 구현이라고 판단했습니다. 하지만 기회가 된다면 시간을 내어 구현해보고 싶습니다.

과제 피드백

과제를 수행함과 동시에 학습효과를 얻어가기에 적절한 과제였다고 생각합니다. 다루고싶던 주제의 글도 써보고 좋은 경험이었습니다.

학습 갈무리

리액트의 렌더링의 단계.

라이프사이클에 따라 렌더링 단계별 어떤 일이 일어나는지 자세히 알고싶어 공부한 내용을 기록한 글입니다. 리액트의 렌더링 단계와 라이프사이클

메모이제이션에 대한 나의 생각을 적어주세요.

실제 메모이제이션 훅을 사용하던 경험을 떠올려가며 작성한 글입니다. 메모이제이션은 무거운 연산이 필요할 때

컨텍스트와 상태관리에 대한 나의 생각을 적어주세요.

상태관리의 방법에 따라 리렌더 성능이 어떻게 달라지는지 공부 해 본 것과, 평소 상태관리 라이브러리를 사용하면서 느꼈던 저의 생각을 함께 담은 글입니다. 프롭스 드릴링 vs 컨텍스트 vs 상태관리 라이브러리

리뷰 받고 싶은 내용

코드리뷰는 아니지만 과제를 수행하면서 코치님의 상태관리 방법이나 용도에 대한 생각을 듣고싶어졌습니다.

  • 어떤 방식으로 상태 관리를 하는 것을 선호하시는지(방법론, 상태관리 라이브러리 종류 등)
  • 여러 팀이나 프로젝트 환경에서 상태관리 라이브러리를 사용해 보셨을텐데 어떤 불편함을 겪었고 어떻게 해결하셨는지
    • 저의 경우 전역 상태관리의 특성 상 특히나 팀 협업 시 관리되지 못하는 스토어가 증식하여 관리가 어려워서 합리적인 해결책을 생각해보고 있습니다.
  • 상태관리에 대한 베스트프랙티스나 잘 할 수 있는 방법론을 다루는 책이나 글이 있다면 소개해주시면 감사할 것 같습니다.

과제 피드백

안녕하세요 유열, 수고하셨습니다! 이번 과제는 React의 내장 훅들을 직접 구현해보면서 프레임워크가 어떻게 상태를 관리하고 최적화하는지 깊이 이해하는 것이 목표였어요. 정유열님의 코드와 회고를 보니 이런 학습 목표를 충분히 달성했다 느껴지네요.

특히 useShallowState를 구현하면서 setState가 동일한 값에 대해서는 리렌더링을 하지 않는다는 사실을 발견하고, 그럼에도 불구하고 참조값의 경우에는 얕은 비교가 여전히 중요하다는 걸 알게 되었다는 점이 좋네요. 사실 이러한 정보들은 이론만 공부할때에는 그냥 지나치기 쉬운데 이렇게 직접 구현을 하면서 공부하다보면 경험을 통해 지식이 완성이 된다 생각합니다!

코드를 살펴보니 일관성 있는 코딩 스타일과 early return을 활용한 명확한 분기 처리, 그리고 타입 안정성을 고려한 구현 좋았습니다.

createObserver에서 useSyncExternalStore에 적합한 subscribe 함수로 store, storage, router의 유기적 연결을 파악하는 과정에서 어려움을 겪으셨다고 하셨는데, 이런 고민 과정 자체가 정말 소중한 학습 경험이에요. 답습을 하더라도 왜 그럴까 고민을 해보는 것 자체가 더 신경써서 뭘 알아야 하는지를 생각하게 만들어주었을거에요!

과제의 수행은 결과가 아니라 그 과정에서 오는 학습과 이러한 과정 자체 알려주고 싶은 것이기에 결과보다는 이 과정이 중요한거죠!

이번 과제를 통해 메모이제이션이 만능이 아니라는 깨달음과 함께 구조적 개선의 중요성을 인식하신 것도 훌륭한 성과입니다. 실제로 성능 최적화는 단순히 메모이제이션만으로 해결되는 것이 아니라, 적절한 아키텍처와 상태 설계가 더 중요한 경우가 많지요 수고하셨습니다!!


Q) 어떤 방식으로 상태 관리를 하는 것을 선호하시는지(방법론, 상태관리 라이브러리 종류 등)

저는 tanstackQuery와 jotai를 사용하고 선호했습니다. 대부분의 경우 데이터를 다루는 것은 서버로직에 있으므로 API를 다루는 tanstackQuery로 충분하고 나머지 언어, 설정, 회원정보 등등은 jotai를 통해서 개발했어요. jotai를 좋아했던건 React 컴포넌트에서 개발을 하고 난 이후에 그 코드를 그대로 jotai로 옮겨놓기만 하면 되니까 그런 직관성과 편리성 측면에서 좋아했습니다.

Q) 여러 팀이나 프로젝트 환경에서 상태관리 라이브러리를 사용해 보셨을텐데 어떤 불편함을 겪었고 어떻게 해결하셨는지 저의 경우 전역 상태관리의 특성 상 특히나 팀 협업 시 관리되지 못하는 스토어가 증식하여 관리가 어려워서 합리적인 해결책을 생각해보고 있습니다.

=> 팀 차원에서 상태관리의 경우 어떤 상태관리를 사용하는 것보다 어떤 인터페이스를 쓸 것인가? 하는 것을 함께 결정하는 것이 중요합니다. 사실 상태관리를 구현의 문제라기 보다는 사용의 문제이니까요.

=> 그래서 언어는 어떻게 할래? useLocale? useLanguage? 값은 함수는? 이런 인터페이스들을 사전에 합의하고 새로운 전역상태가 필요할때마다 그 인터페이스만 합의해두고 나면 믿고 쓰면 되고 문제가 생겨도 인터페이스는 변하지 않으므로 인터페이스를 변경하지 않고 개발한다는 원칙을 지킨다면 무분별해지는건 어느정도 방지 할 수 있습니다.

=> 그리고 당연히 모두가 사용하는 layer인 만큼 누군가의 충분한 책임감을 가지고 담당해야하 하는 담당자 지정은 반드시 필요하다고 생각해요 :)

Q) 상태관리에 대한 베스트프랙티스나 잘 할 수 있는 방법론을 다루는 책이나 글이 있다면 소개해주시면 감사할 것 같습니다.

=> 책이나 글은 잘 떠오르지 않네요. 뭔가 상태관리만 다뤄낸 책을 따로 본 기억이 없어서 제가 찾아지면 공유할게요. 클린코드의 챕터의 2-2, 2-3이 그 상태관리를 다루고 있는만큼 해당 챕터에서 본격적으로 익혀보자구요!

수고하셨습니다. 정유열님의 깊이 있는 탐구 정신과 체계적인 학습 접근법이 앞으로도 큰 성장의 원동력이 될 것이라 확신합니다. 클린코드 챕터도 화이팅입니다!