Skip to content

[2팀 정나리] Chapter2-2. 나만의 React 만들기 - #5

Open
naringst wants to merge 20 commits into
hanghae-plus:mainfrom
naringst:main
Open

naringst wants to merge 20 commits into
hanghae-plus:mainfrom
naringst:main

Conversation

@naringst

@naringst naringst commented Nov 15, 2025

Copy link
Copy Markdown

과제 체크포인트

배포 링크

https://naringst.github.io/front_7th_chapter2-2/

기본과제

Phase 1: VNode와 기초 유틸리티

  • core/elements.ts: createElement, normalizeNode, createChildPath
  • utils/validators.ts: isEmptyValue
  • utils/equals.ts: shallowEquals, deepEquals

Phase 2: 컨텍스트와 루트 초기화

  • core/types.ts: VNode/Instance/Context 타입 선언
  • core/context.ts: 루트/훅 컨텍스트와 경로 스택 관리
  • core/setup.ts: 컨테이너 초기화, 컨텍스트 리셋, 루트 렌더 트리거

Phase 3: DOM 인터페이스 구축

  • core/dom.ts: 속성/스타일/이벤트 적용 규칙, DOM 노드 탐색/삽입/제거

Phase 4: 렌더 스케줄링

  • utils/enqueue.ts: enqueue, withEnqueue로 마이크로태스크 큐 구성
  • core/render.ts: render, enqueueRender로 루트 렌더 사이클 구현

Phase 5: Reconciliation

  • core/reconciler.ts: 마운트/업데이트/언마운트, 자식 비교, key/anchor 처리
  • core/dom.ts: Reconciliation에서 사용할 DOM 재배치 보조 함수 확인

Phase 6: 기본 Hook 시스템

  • core/hooks.ts: 훅 상태 저장, useState, useEffect, cleanup/queue 관리
  • core/context.ts: 훅 커서 증가, 방문 경로 기록, 미사용 훅 정리

기본 과제 완료 기준: basic.equals.test.tsx, basic.mini-react.test.tsx 전부 통과

심화과제

Phase 7: 확장 Hook & HOC

  • hooks/useRef.ts: ref 객체 유지
  • hooks/useMemo.ts, hooks/useCallback.ts: shallow 비교 기반 메모이제이션
  • hooks/useDeepMemo.ts, hooks/useAutoCallback.ts: deep 비교/자동 콜백 헬퍼
  • hocs/memo.ts, hocs/deepMemo.ts: props 비교 기반 컴포넌트 메모이제이션

과제 셀프회고

최초 시도는 createElement부터 이해하면서 약간의 AI를 덧붙여 구현하려고 했습니다. 그런데 그렇게 했더니 진도가 너무 안나가기도 하고, 회사 일이 급격하게 바빠진 관계로... 우선 AI로 과제를 수행하는 전략으로 수정했습니다.
AI 구현 후 내용을 익히고 다시 구현하려고 했는데, 내부 구현을 이해하는데에 시간을 많이 쓰게 되어 일단 내용 이해까지만 하였고, 다시 직접 구현해보는 과정은 이후에 해볼 예정입니다! ㅠ.ㅠ

1차 구현

  • AI를 활용해서 테스트 케이스 별로 빈칸 채우기
  • 프롬프팅 내용은 테스트 케이스를 수정하지 않도록 하기 위해서 아래와 같이 입력했습니다.
    "다른 부분 테스트 코드 깨지지 않게" + " 테스트 코드 내부에서 사용하는 함수들 코드 작성"
스크린샷 2025-11-19 오전 3 23 25 스크린샷 2025-11-19 오전 3 23 51

1차 구현 후 2차 구현 전

  • AI가 짜준 코드를 따라 대충 어떤 흐름으로 코드를 작성해봤으면 좋았을지, 어떤 식으로 코드를 작성할 수 있었는지 복습
  • React, Preact 코드를 보면서 createElement, createContext, useState, useMemo .... 함수 구현 확인하기

2차 구현(추후)

  • 직접 구현해보기

아하! 모먼트 (A-ha! Moment)

지난 주차 질문에서 이벤트 핸들러를 왜 최상단에 두고 써야 하는지에 대해 질문드렸었는데, 리액트의 동작하는 방식을 보다 보니 이유를 조금 알게 된 것 같습니다.
리액트의 동작 과정은 createElement -> render phase -> commit phase가 있고, commit phase에서는 실제 DOM을 업데이트 해줍니다. 이 과정에서 이벤트 핸들러가 변경되었을 때 이벤트 핸들러를 변경해주는데, 편하게 변경해주려면 다른 부분에 대한 조작 없이 딱 이벤트 핸들러 호출 함수 부분만 변경해주면 좋을 것 같습니다.
만약 페이지 단위로 이벤트를 관리했다면 트리에서 해당 페이지를 찾는 과정을 거치는 번거로움이 있지 않았을까? 하고 생각했습니다!

기술적 성장

javasript 원시값 관련

  • js의 전체 원시값에 뭐가 있는지 암기 ㅋㅋ (자스의 7원시값 : num big bool null st und sym- 넘빅불 널스트 언디심)
    • 보면 알긴 하겠지만... 다 외워서 툭하고 머릿속에서 나올 정도는 아니었습니다. 그런데 createElement 에서도 그렇고 모든 값에 대한 처리가 필요해서 그냥 외워서 쓰자... 하고 외웠습니다 ㅋㅋ
  • isNaN, Array.isArray, Object.is, Object... 등 타입 관련 검증 함수들 익히기
    • Object.is 함수 : === 과 거의 동일한데, Object.is(NaN, NaN)이 true, Object.is(+0, -0) 도 true라는 점이 ===과 다르다!
    • Object.is의 역사... ES6에서 추가된 함수로, NaN비교나 +0, -0 비교때문에 추가. 자바스크립트 내부에서 사용하는 “SameValue 알고리즘”을 외부에서도 활용할 수 있게 만든 함수
    • isNaN

얕은비교와 깊은 비교

  • 제가 뭔가 거꾸로 알고 있었습니다. 얕은 비교가 값만 비교하는 거고, 깊은 비교가 참조를 비교하는 거라고 생각했는데, 거꾸로였습니다!!!
  • 얕은 비교가 참조만 비교해서 -> 결국 1depth의 비교가 되고, 깊은 비교가 값까지 비교를 해서 -> 2depth이상도 제대로 비교가 된다

“참조 비교 = 객체 내부까지 안 들어간다 = 1depth 비교만 한다” 이게 어떻게 되는 걸까? 1depth 비교와 어떻게 연결되지??
얕은 비교(shallow equal)는 기본적으로 다음만 비교함:

  • Primitive 값 → 값 자체 비교
  • Object, Array → 참조 비교
  • 그니까 메모리로 따지면 얕은 비교는 메모리 끝자락에 있는 값만 비교를 하는건데, 원시 값은 바로 참조되는 메모리에 값이 있으니까 값끼리 비교가 되고, object, array는 바로 참조되는 메모리에 값이 있는게 아니라 포인터가 있으니까 참조되는 메모리 주소만 비교하게 되는것! 따라서 얕은 비교에서 2depth 객체는 비교가 안되는게, 기본적으로 객체는 얕은 비교를 해서는 중첩된 두 객체가 같다고 나올 수가 없음!!! 이라고 이해했습니다.

리액트 관련 학습 내용

너무 길어져서 노션에서 정리한 내용을 첨부하겠습니다!
이번 과제를 구현보다는 거의 개념 위주로 학습해서 내용이 좀 많습니다...!
최대한 동작원리를 학습하고, 그걸 기반으로 실제 리액트의 구현과, 우리 과제에서 어떤 식으로 처리하고 있는지를 비교해서 학습했습니다!

목차

  • 리엑트 전체 동작 과정
  • createElement의 역할
  • Render Phase(Reconciliation + Diffing + fiber 생성)
  • Commit Phase
  • Context 내부 요소들이 존재하는 이유와 각각의 역할
  • Fiber의 도입 이유와 특징
  • Hooks 과정 이해
    • 상태 변경 시 리액트의 동작 과정

https://naringst.notion.site/5-2b239fba054a8062b282d67919feb377?source=copy_link

코드 품질

AI가 작성해줘서 거의 깔끔한데, any 타입을 좀 많이 쓰고 있어서 그 부분은 아쉽습니다!

학습 효과 분석

실제 제가 코드를 다시 작성을 많이 못해봤지만, 그래도 배운 내용은 아주 많았다고 생각합니다. 리액트의 일부분, hook의 원리나 router, 생명주기에 대해서는 학습한 적이 있지만, 이렇게 내부의 동작원리를 하나하나 따라가면서 학습했던 적은 없었습니다. 따라서 이번 기회로 세부적인 내용들을 매우 자세하게 학습할 수 있어서 매우 !! 좋았습니다.
다만 구현의 과정이나 실제 구현 부분은 많이 해보지 못해서 다소 아쉽습니다..! 새로 파둔 새 브랜치에서 꾸준히 구현해보겠습니다!

과제 피드백

어느정도 틀이 정해져 있어서 좋은 부분도 있었고, 오히려 어떤 식으로 저 함수들을 사용해야 하는지 모르겠어서 어려운 분도 있었습니다. 또한 내부 변수들도 어떤 용도로 사용해야 하는지 잘 몰라서 이 부분도 어려웠습니다..!! ㅠ.ㅠ

리뷰 받고 싶은 내용

  1. 과제를 진행하면서 먼저 이론을 학습하고 -> 그에 대한 구현을 다시 해보려고 했습니다. 그래서 AI로 구현하고 -> 그 코드를 기반으로 이해를 더하고 -> 다음에 구현 계획이었는데, 혹시 먼저 구현을 어떻게 할지를 먼저 고민했다면 더 학습에 좋았을까요? 다른 주차에 반영해보면 좋을 것 같아서 질문드립니다!

  2. 세부적인 구현들 - 어떤 타입을 어떻게 처리하고 왜 처리하고, 중첩 구조는 어떻게 처리하고... 이 코드를 보고 이해하는 것도 다소 어려웠습니다. 구체적으로는 아래 enqueue와 withEnqueue 부분이었는데요, 이런 부분을 좀 더 잘 이해하고 파악하려면 어떤 연습을 하면 좋을까요?

/**
 * 작업을 마이크로태스크 큐에 추가하여 비동기적으로 실행합니다.
 * 브라우저의 `queueMicrotask` 또는 `Promise.resolve().then()`을 사용합니다.
 */
export const enqueue = (callback: () => void): void => {
  if (typeof queueMicrotask === "function") {
    queueMicrotask(callback);
    return;
  }

  Promise.resolve()
    .then(callback)
    .catch((error) => {
      setTimeout(() => {
        throw error;
      });
    });
};

/**
 * 함수가 여러 번 호출되더라도 실제 실행은 한 번만 스케줄링되도록 보장하는 고차 함수입니다.
 * 렌더링이나 이펙트 실행과 같은 작업의 중복을 방지하는 데 사용됩니다.
 */
export const withEnqueue = <T extends AnyFunction>(fn: T) => {
  let scheduled = false;

  return (...args: Parameters<T>) => {
    if (scheduled) return;
    scheduled = true;

    enqueue(() => {
      scheduled = false;
      fn(...args);
    });
  };
};

@naringst naringst changed the title [2팀 정나리] [2팀 정나리] Chapter2-2. 나만의 React 만들기 Nov 15, 2025

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant