본문 바로가기
개발

[항해플러스] React Hooks 직접 구현하기 (useRef, useMemo, useCallback, ...)

by soyooooon 2024. 10. 12.
반응형

구현한 Hooks를 활용하여 샘플 애플리케이션 최적화 진행

이번 주 과제

  • 얕은 비교와 깊은 비교 로직 구현
  • useRef 구현
  • 위 비교 함수와 직접 구현한 useRef를 활용하여 memo, useMemo, useCallback 구현
  • 샘플 애플리케이션 최적화 진행 (직접 구현한 훅 활용, 하나로 합쳐져 있는 Context 분리)

이번 주 새롭게 알게 된 내용

Object.is()

// Before
 
if (typeof objA !== typeof objB) return false;
if (objA === null || typeof objA !== "object") return objA === objB;
 
 
// after
 
if (Object.is(objA, objB)) return true;
if (typeof objA !== "object" || typeof objB !== "object") return false;

위 코드는 objA와 objB의 일치여부에 따라 true/false를 내뱉는 함수의 일부이다. 기존보다 직관적으로 코드가 바뀌었으면 하는 마음이 있었고, 코드리뷰를 하다가 Object.is를 발견하여 이것을 활용하여 코드를 개선했다. Object.is()를 통해 일치하면 바로 true를 return 하고, 나머지 object가 아닌 경우에는 일괄 false를 return 하니 true/false로 명확히 나뉘어 더 직관적으로 코드가 개선되었다.

===과는 +0, -0의 비교 (false), NaN과 NaN의 비교(true)를 제외하고는 동일하다.

Object.prototype.hasOwnProperty()

// Before
if (objA[key] !== objB[key]) return false;
 
// After
if (!Object.prototype.hasOwnProperty.call(objB, key) || objA[key] !== objB[key]) return false;번주차 궁금했던 점

기존에는 objA[key] !== objB[key]로만 조건식을 두었지만, 이 함수가 여러 환경의 프로젝트에서 사용되는 것을 가정했을 때 조금 더 안정성을 갖추면 좋겠다는 생각을 하게 되었고 코드 리뷰를 주신 분의 의견에 따라 hasOwnProperty를 조건에 추가하게 되었다. 만약 누가 임의로 prototype에 무언가를 추가하게 된다면 이 경우에 영향을 받을 수 있기 때문에 이 조건도 같이 추가하게 되었다. 다음은 개선한 코드이다.

이번 주 궁금했던 내용

다음은 과제를 진행하면서 궁금했던 점들을 질문하고 답변을 얻었던 부분들에 대해 정리했다.

Q. 과제 폴더 구조를 어떻게 나누실지 궁금합니다!

  • context, provider, hook, type 등 나눌 수 있는 최대한으로 나눈다
  • context, provider, hook, type을 하나로 합친다.

A. 이렇게 하는 편이랍니다!

  • Context/Provider 자체는 한 파일에 정의
  • Context를 사용하는 로직은 다른 파일에 정의 (use-)

이에 더해 아예 합치는 것도 괜찮을 것 같다고 말씀 주셨고, 사실 팀원들과 구조에 대한 일관성만 맞춘다면 어떤 구조로 짜든 괜찮다는 말도 덧붙여주셨다.

// /providers/UserProvider.tsx
export type UserContextType = {};

export const UserContext = createContext(null);

export default function UserProvider({ children }) {
  const contextValue = { ... }
  return (
    <UserContext.Provider value={contextValue}>
      {children}
    </UserContext.Provider>
  )
}

// /providers/hooks/useUserContext.ts
import { UserContext } from '../UserProvider';

export default function useUserContext() {
  return useContext(UserContext)
}

Q. 정렬 순서가 다른 배열의 shallowEquals

  • {a: 1, b: 2}와 {b: 2, a: 1}는 같다고 보는데, 그럼 [1, 2]와 [2, 1]도 같다고 봐야 하나요?
  • oo님이랑 잠깐 토론을 했을 때, 배열은 index로 요소를 비교하고 index가 가리키는 요소가 다르기 때문에 다르다고 보는 게 맞지 않을까?라고 이야기 했는데 코치님의 의견과 이유도 궁금합니다.
// 객체는 순서가 바뀌어도 키값이 동일하기 때문에 동일한 것으로 기대
expect(shallowEquals({ a: 1, b: 2 }, { b: 2, a: 1 })).toBe(true);

// 그렇다면... 이 경우는 index가 다르기 때문에 다르다고 봐야하나요? 아니면 구성요소가 같기 때문에 같다고 봐야하나요?
expect(shallowEquals([1, 2], [2, 1])).toBe(?);

A. 다르게 봐야 함!

예시로 들어주신 코드 중 a[0] === b[0], obj1.a === obj2.a를 같이 나열하여 설명해 주셨는데 바로 납득이 됐다.

////// 의견
const a = [1, 2]
const b = [2, 1]

a[0] === b[0]; // 이건 다르니까!

const obj1 = { a: 1, b: 2 }
const obj2 = { b: 2, a: 1 }

obj1.a === obj2.a; // 이건 같으니까!

이번 주 리뷰 및 칭찬노트

이번주부터 페어팀이 시작됐다. ZEP 기준 바로 아래에 있던 18팀이랑 페어팀이 되었는데 그래도 이전 주차들에서 같이 과제를 진행한 적이 있거나 네트워킹 때 만났던 분들이 계셔서 크게 어려움은 없었지만 아직은 어색함이 약간 남아있긴 한 것 같다...! (아마 과제하면서 같이 밤을 새우다 보면 금방 한 팀처럼 느껴질 것 같다는 생각이...😂)

  • 팀/페어팀/다른 분들 코드리뷰를 적극적으로 진행하면서 내 코드에서 개선해야 될 부분이 있는지 혹은 놓친 부분이 있는지를 체크하고 반영했다.
  • 배운 내용을 토대로 회사 코드 최적화에도 일부 적용했다.
  • 주어진 과제 외에도 구조적인 고민을 했다. 여러 케이스들을 살펴보고 질문하며 적절한 방향성에 대한 기준을 하나 세울 수 있었다.

 

3주 차 PR - https://github.com/hanghae-plus/front_3rd_chapter1-3/pull/14

3주 차 개인레포 - https://github.com/soyoonJ/front_3rd_chapter1-3

 

[17팀 정소윤][Chapter 1-3] React, Beyond the Basics by soyoonJ · Pull Request #14 · hanghae-plus/front_3rd_chapter1-3

과제 체크포인트 기본과제 shallowEquals 구현 완료 deepEquals 구현 완료 memo 구현 완료 deepMemo 구현 완료 useRef 구현 완료 useMemo 구현 완료 useDeepMemo 구현 완료 useCallback 구현 완료 심화 과제 기본과제에

github.com

 

 

참고문서

Object.is()

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/is

 

항해 추천인 코드 (20만원 할인) - IXtXJj

반응형