hyojin-k 님의 상세페이지[3팀 김효진] Chapter 1-3. React, Beyond the Basics

과제 체크포인트

배포 링크

https://hyojin-k.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 개선

과제 셀프회고

기술적 성장

  • Object.is()

    • 초기 코드에 사용해보진 않았으나, 다른 사람들의 코드를 보면서 많이 발견되었던 Object.is()
    • === 와 비슷한 결과를 보여주긴 하지만 하단의 경우처럼 특수한 케이스에서는 결과 값이 다름
    -0 === +0 // true
    Object.is(-0, +0) // false
    
    NaN === NaN // false
    Object.is(NaN, NaN) // true
    
  • Record<string, unknown> 는 언제 사용해야하는가

    • shallowEquals.ts에서 const keysA = Object.keys(a)로 했더니 타입 에러 발생
    • export const shallowEquals = (a: unknown, b: unknown) 함수 매개변수가 unknown 타입으로 정의되어 있기 때문인데, 어떤 값이든 받을 수는 있지만 해당 값을 사용하기 전에 객체 프로퍼티 접근을 위해 타입을 명시적으로 확인하거나 캐스팅해야함
    • 동일한 방식으로 const objA = a as { [key:string] : unknown} 가 있는데 생각해보니 이렇게는 사용해본 적이 있음
    • 타입 지정을 함으로써 런타임 에러를 방지하고 객체 프로퍼티에 안전하게 접근할 수 있음
  • useRef

    • 솔직히 처음에는 useState를 사용해서 useRef를 어떻게 만들라는건지 이해도 못하고 감도 안와서 다른 분들의 코드를 염탐했습니다. 정답을 알려조…! 근데 마치 짠 것 처럼 같은 코드를 작성한 것이 아닌가…?

      export function useRef<T>(initialValue: T): { current: T } {
        const [ref] = useState(() => ({ current: initialValue }));
      
        return ref;
      }
      
    • const [state] = useState(initialValue) 이렇게 setter 함수를 사용하지 않게되면 해당 객체를 변경해도 리렌더링이 발생하지 않는다..!

자랑하고 싶은 코드

딱히 자랑하고 싶은 코드는 없지만 그나마 꼽아보자면 shallowEquals/deepEquals를 간단하게 리팩토링을 해보았다…? 해당 코드는 하단 개선이 필요한 코드에서 동일하게 언급하고 있습니다.

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

  • shallowEquals / deepEquals 코드 개선 필요

    AS-IS

    • 조건문 중첩이 깊게 되어 있어서 가독성이 떨어짐
    • 배열을 별도로 처리할 필요가 없음
    export const shallowEquals = (a: unknown, b: unknown) => {
      if (a === b) return true;
    
      if (a !== null && b !== null) {
        // 배열 비교
        if (Array.isArray(a) && Array.isArray(b)) {
          if (a.length === b.length && a.every((item, index) => item === b[index])) {
            return true;
          }
          return false;
        }
    
        // 객체 비교
        if (typeof a === "object" && typeof b === "object") {
          const objA = a as Record<string, unknown>;
          const objB = b as Record<string, unknown>;
    
          const keysA = Object.keys(objA);
          const keysB = Object.keys(objB);
    
          if (keysA.length !== keysB.length) {
            return false;
          }
    
          for (const key of keysA) {
            if (objA[key] !== objB[key]) return false;
          }
    
          return true;
        }
      }
    
      return false;
    };
    

    TO-BE

    • 조건문 중첩을 제거함으로써 가독성 향상
    • 배열도 객체로 취급하여 Object.keys()를 통해 인덱스를 키로 비교하므로 배열 비교 조건을 제거
    • === 대신 Object.is() 사용
    export const shallowEquals = (a: unknown, b: unknown) => {
      if (Object.is(a, b)) return true;
    
      if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) return false;
    
      // 객체 비교
      const objA = a as Record<string, unknown>;
      const objB = b as Record<string, unknown>;
    
      const keysA = Object.keys(objA);
      const keysB = Object.keys(objB);
    
      if (keysA.length !== keysB.length) {
        return false;
      }
    
      for (const key of keysA) {
        if (!Object.is(objA[key], objB[key])) return false;
      }
    
      return true;
    };
    
    

학습 효과 분석

  • 그동안 무의식적으로 사용하고 있던 hook들에 대해 좀 더 깊게 생각해볼 수 있었습니다. 당장 상단에서 언급했던 useRef 구현에서도 느꼈듯이 당연하게 쓰고있지만 놓치는 부분이 많다는걸 알게되었습니다. 앞으로 실무에서 hooks를 사용할 때 좀 더 신경쓰면서 효과적으로 사용할 수 있길…!! 추가적으로 사용해보지 않은 문법, hook에 대해서 알아볼 수 있는 기회였습니다.
  • 과제를 진행하면서 다른 분들이 정리해준 글, pr들을 많이 참고했는데 많은 도움을 받을 수 있어서 좋았습니다. 다만 제가 스스로 코드를 뜯어보거나 분석해보는 등의 경험이 덜 한 채로 다른 분들이 정리해둔 글을 읽다보니 ‘나도 저렇게 직접 탐구를 해보고싶다..!’라는 자극을 받게 되더라고요. 다음 과제에서는 한 번 도전해보겠습니다.

과제 피드백

  • 어느정도 답이 정해져있는 과제라 지금까지의 과제에 비해서는 쉬운 듯 하면서도(일단 1,2주차보다 AI의 도움을 덜 받음) 지금껏 무의식적으로 사용하고 있던 hook들에 대해 조금 더 깊이 있게 알아볼 수 있는 과제였습니다.

학습 갈무리

리액트의 렌더링이 어떻게 이루어지는지 정리해주세요.

리액트의 렌더링 과정은 UI를 효율적으로 갱신하기 위해 최초 렌더 → 가상 DOM 생성 → Reconciliation(비교) → 실제 DOM 변경의 흐름으로 이루어집니다.

  • 최초 렌더 - createRoot().render()를 호출하면서 최초 렌더링 시작
  • 가상 DOM 생성 - 루트 컴포넌트부터 시작해서 모든 컴포넌트를 순회하며 가상 DOM 트리 생성
  • Reconciliation - 상태나 props 변경에 따라 이전 가상 DOM 트리와 새로운 가상 DOM 트리를 비교해서 변경사항 감지
  • 실제 DOM 변경 - 비교 결과 변경된 사항만 최소한으로 업데이트

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

한 때 회사에서 팀원들과 나눴던 얘기 중 메모이제이션에 관한 내용이 있었는데요, ‘useMemo와 useCallback을 많이 사용하는 것이 오히려 성능에 좋지 않다고 하더라.’라는 이야기였습니다. 실제로 저희는 쓸 수 있는 거의 모든 곳에 useMemo와 useCallback을 사용하고 있습니다. 이 때 당시에는 스쳐지나가는 주제라 제대로 된 결론이 나지는 않았었네요. 그런데 이번 주에 다른 팀의 멘토링 주제에서도 비슷한 내용이 언급되었고, 코치님의 답변은 ‘적절한 순간에 메모이제이션을 쓰기로 하면서부터 오히려 개발하는데 병목이 생길 수 있고 생산성이 떨어질 수 있으니 이럴거면 다 적용하는게 좋은 것 같다’ 였습니다. 오? 그럼 오히려 제대로 쓰고 있었을지도?^^ㅎㅎ 명쾌한 답변 인 듯 하면서도 그렇다면 메모이제이션을 적절하게 써보기 위해 노력해본 적은 있는가? 모든 코드에 메모이제이션을 쓰고 있는 지금 상황이 선택적 메모이제이션에 대해 불편함을 느끼고 난 후의 결론인가? 라고 생각했을 땐 ‘아니!’ 라는 생각까지 도달했습니다. 프로젝트를 진행하면서 필요한 곳에서만 메모이제이션을 하는 방식을 적용해 본 경험이 있었다면 현재의 상황에 대해 가지고 있던 의문점을 좀 더 빨리 해소할 수 있었을 것 같습니다.

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

리뷰 받고 싶은 내용

과제 피드백

안녕하세요 효진님!! 다시 만나서 너무 반가워요 ㅋㅋㅋ

과제를 진행하면서 다른 분들이 정리해준 글, pr들을 많이 참고했는데 많은 도움을 받을 수 있어서 좋았습니다. 다만 제가 스스로 코드를 뜯어보거나 분석해보는 등의 경험이 덜 한 채로 다른 분들이 정리해둔 글을 읽다보니 ‘나도 저렇게 직접 탐구를 해보고싶다..!’라는 자극을 받게 되더라고요. 다음 과제에서는 한 번 도전해보겠습니다.

지금 과제에서도 충분히 잘 해주고 있어요! 처음부터 많은걸 하기보다 조금씩 조금씩 효진님의 바운더리를 넓혀가는 방식으로 시도해보시면 좋답니다 ㅎㅎ

한 때 회사에서 팀원들과 나눴던 얘기 중 메모이제이션에 관한 내용이 있었는데요, ‘useMemo와 useCallback을 많이 사용하는 것이 오히려 성능에 좋지 않다고 하더라.’라는 이야기였습니다. 실제로 저희는 쓸 수 있는 거의 모든 곳에 useMemo와 useCallback을 사용하고 있습니다. 이 때 당시에는 스쳐지나가는 주제라 제대로 된 결론이 나지는 않았었네요. 그런데 이번 주에 다른 팀의 멘토링 주제에서도 비슷한 내용이 언급되었고, 코치님의 답변은 ‘적절한 순간에 메모이제이션을 쓰기로 하면서부터 오히려 개발하는데 병목이 생길 수 있고 생산성이 떨어질 수 있으니 이럴거면 다 적용하는게 좋은 것 같다’ 였습니다. 오? 그럼 오히려 제대로 쓰고 있었을지도?^^ㅎㅎ 명쾌한 답변 인 듯 하면서도 그렇다면 메모이제이션을 적절하게 써보기 위해 노력해본 적은 있는가? 모든 코드에 메모이제이션을 쓰고 있는 지금 상황이 선택적 메모이제이션에 대해 불편함을 느끼고 난 후의 결론인가? 라고 생각했을 땐 ‘아니!’ 라는 생각까지 도달했습니다. 프로젝트를 진행하면서 필요한 곳에서만 메모이제이션을 하는 방식을 적용해 본 경험이 있었다면 현재의 상황에 대해 가지고 있던 의문점을 좀 더 빨리 해소할 수 있었을 것 같습니다.

아마 9주차 ~ 10주차 과제에서 메모이제이션에 대해 조금 더 다룰 것 같은데요, 이 때 효진님께서 잘 학습할 수 있도록 설계해보겠습니다 ㅋㅋㅋ

3주차 과제 진행하느라 고생하셨어요! 특별한 질문은 없는 것 같아서, 일단 마무리하겠습니다 ㅎㅎ