[8팀 현지수] Chapter 1-3. React, Beyond the Basics#42
[8팀 현지수] Chapter 1-3. React, Beyond the Basics#42hyunzsu wants to merge 17 commits intohanghae-plus:mainfrom
Conversation
unseoJang
left a comment
There was a problem hiding this comment.
지수님~1-3 과제 하느라 수고 많았어요
혹시 React 공식문서 공부를 한번 했나요? 1년차 답지 않게 React 공부를 하고 나서 과제를 한 느낌이 드네요? 유열님이랑 코드가 가장 유사해요, 그래서 제가 따로 지적할 부분도 별로 없는 것 같네요(수준이 높다는 얘기...)
PR만 열심히 쓰면 BP각인데...하아...
여튼 2-1과제도 화이팅하시고 PR신경써서 BP한번 받아봅시다
There was a problem hiding this comment.
지수님도 유열님이랑 동일하게 useAutoCallback으로 진행해 주셨군요, 혹시 useAutoCallback으로 진행한 이유를 알수 있을까요? 지수님 생각이 듣고싶네요
그와 별개로 코드는 굉장히 잘 구성해주셧네요
재사용 가능한 유틸로 만들고 싶다고 하면, 지수님이 남겨준
https://github.com/hanghae-plus/front_6th_chapter1-3/pull/45/files#r2230056660
가 있습니다.
지수님 코드 우라까이 한거지만 확인해보면 좋을 것 같아요
| * @returns 두 값이 깊은 수준에서 동일하면 true, 다르면 false | ||
| */ | ||
| export function deepEquals(objA: unknown, objB: unknown): boolean { | ||
| // 1. 참조 동일성 체크 |
There was a problem hiding this comment.
이부분은 제생각보다 훨신 더 잘 구성해주셨네요, AI를 돌려도 detail이 다르긴하네요...
typeof objA !== typeof objBai 돌려도 굳이 이 코드 없어도 된다 이정도만 지적해주는거보면 지수님이 코드를 잘 구성하시는 편이시네요
There was a problem hiding this comment.
위에 내용이랑 동일한부분 뺴면 얕은비교 shallowEquals구현을 잘했네용
|
|
||
| const defaultSelector = <T, S = T>(state: T) => state as unknown as S; | ||
|
|
||
| /** |
There was a problem hiding this comment.
주석 세세하게 달아서 좋아요, AI가 적어준 주석이라도 가독성이 좋네요
| // useState를 사용하여 상태를 관리하고, shallowEquals를 사용하여 상태 변경을 감지하는 훅을 구현합니다. | ||
| return useState(initialValue); | ||
| /** | ||
| * 얕은 비교를 통해 불필요한 리렌더링을 방지하는 useState의 개선 버전입니다. |
There was a problem hiding this comment.
이런 주석 너무 좋아요, 가독성도 올라가고 만약 협업을 한다면 이 주석을 보고 안에 함수 내용을 확인하는 것이 좋은것같아요
과제 체크포인트
배포 링크
https://hyunzsu.github.io/front_6th_chapter1-3/
기본과제
equalities
hooks
High Order Components
심화 과제
hooks
context
과제 셀프회고
과제를 진행하면서 상세 문서화 작성했습니다.
기술적 성장
React hooks 내부 동작 원리 이해: useState, useRef, useMemo, useCallback의 내부 구현을 직접 작성하며 React의 렌더링 최적화 메커니즘을 체득
비교 알고리즘 구현: shallowEquals와 deepEquals 함수를 통해 JavaScript 객체 비교의 미묘한 차이점 학습
최적화 전략 구현: useAutoCallback, useShallowState, useShallowSelector 등 실무에서 유용한 커스텀 훅 설계
자랑하고 싶은 코드
ToastProvider의 Context 분리
자주 변하는 상태(message, type)와 거의 변하지 않는 함수들(show, hide)을 별도 Context로 분리하여 불필요한 리렌더링을 방지하였습니다.
학습 효과 분석
React의 메모이제이션이 단순한 캐싱이 아닌, 참조 동일성 기반의 리렌더링 최적화 시스템임을 이해
학습 갈무리
리액트의 렌더링이 어떻게 이루어지는지 정리해주세요.
React의 렌더링 과정은 상태 변경 → 가상 DOM 생성 → 비교(Reconciliation) → 실제 DOM 업데이트 순으로 이루어집니다.
이번 과제에서 useState를 직접 구현하면서 렌더링 트리거의 핵심을 이해했습니다. React는 Object.is()로 이전 값과 새 값을 비교해서 다를 때만 리렌더링을 시작하죠. 그래서 setState([...arr])처럼 새로운 참조를 만들어야 변경을 감지할 수 있어요.
컴포넌트가 리렌더링되면 기본적으로 모든 하위 컴포넌트도 함께 리렌더링됩니다. 이때 Virtual DOM을 통해 이전 트리와 새 트리를 비교하고, 실제로 변경된 부분만 DOM에 반영하는 것이 React의 핵심 최적화입니다.
렌더링 최적화를 위해서는 memo로 컴포넌트 메모이제이션, useMemo로 값 메모이제이션, useCallback으로 함수 메모이제이션을 활용할 수 있습니다. 이들은 모두 얕은 비교를 통해 불필요한 재계산을 방지하는 원리로 동작합니다.
결국 React의 렌더링은 "참조 비교 기반의 변경 감지"와 "Virtual DOM을 통한 효율적인 업데이트"가 핵심이라고 정리할 수 있습니다.
메모이제이션에 대한 나의 생각을 적어주세요.
메모이제이션은 단순한 캐싱이 아니라 의존성 관리가 핵심이라는 걸 깨달았습니다.
useCallback을 직접 구현하면서 의존성 배열의 중요성을 체감했어요. 의존성을 빼먹으면 stale closure 문제가 생기고, 너무 많이 넣으면 매번 새로운 함수가 생성되어 메모이제이션 효과가 사라지죠.
메모이제이션이 필요한 경우는 크게 두 가지입니다. 첫째는 expensive한 계산(복잡한 배열 처리, 수학 연산 등)을 반복하는 경우, 둘째는 자식 컴포넌트의 불필요한 리렌더링을 방지하는 경우죠.
하지만 메모이제이션을 남용하면 오히려 성능이 악화될 수 있습니다. 메모리 사용량이 늘어나고, 얕은 비교 연산 자체도 비용이기 때문이에요. 특히 자주 변경되는 값을 메모이제이션하면 비교 비용만 추가되는 상황이 발생합니다.
컨텍스트와 상태관리에 대한 나의 생각을 적어주세요.
Context와 상태관리가 필요한 이유는 prop drilling 문제와 전역 상태 공유 때문입니다. 깊은 컴포넌트 트리에서 상태를 전달하려면 중간 컴포넌트들이 불필요하게 props를 받아야 하고, 이는 코드의 복잡성을 크게 증가시키죠.
하지만 Context는 양날의 검입니다. ToastContext와 ModalContext를 개선하면서 깨달은 건데, Context 값이 변경되면 Provider 하위의 모든 컴포넌트가 리렌더링됩니다. 이는 성능상 큰 문제가 될 수 있어요.
Context 설계 시 가장 중요한 것은 변경 빈도에 따른 분리입니다. 자주 변하는 상태(input value, loading state)와 거의 변하지 않는 상태(theme, user info)는 별도의 Context로 관리해야 합니다. 또한 useShallowSelector를 구현하면서 느낀 건데, "필요한 데이터만 구독"하는 것이 상태관리의 핵심이에요.
Context의 대안으로는 상태를 적절히 끌어올리기(lifting state up), 컴포넌트 합성 패턴, 또는 외부 상태관리 라이브러리 사용이 있습니다. 특히 복잡한 전역 상태는 Zustand나 Redux 같은 라이브러리가 더 효율적인 구독 메커니즘을 제공하죠.
결론적으로 단순한 상태는 useState로, 중간 복잡도는 Context로, 복잡한 전역 상태는 전용 라이브러리로 접근하는 것이 현실적인 선택이라고 생각합니다. Context는 만능 해결책이 아니라 특정 상황에 적합한 도구로 봐야 해요.
리뷰 받고 싶은 내용
1. deepEquals 순환 참조 처리의 필요성과 구현 방법
현재 deepEquals는 순환 참조 처리 없이 단순 재귀로 구현되어 있습니다.
React의 props나 state에서 순환 참조가 발생하는 실제 사례가 얼마나 빈번한지, 그리고 WeakSet을 사용한 순환 참조 추적 로직의 성능 오버헤드와 메모리 사용량 증가를 고려했을 때 실용적인 개선인지 궁금합니다. 라이브러리 수준에서는 안정성을 위해 필요하지만, 애플리케이션 수준에서는 불필요한 복잡성일 수도 있을 것 같은데 어떤 기준으로 판단하면 좋을까요?
2. useAutoCallback의 개발자 경험
의존성 배열 관리의 복잡성을 해결하기 위해 useAutoCallback을 구현했습니다.
이 접근법이 실제 개발 실무에서 얼마나 유용할지 궁금합니다! 개발자는 의존성을 신경 쓰지 않아도 되는 편의성을 얻지만, 함수가 매번 새로 생성되어도 참조는 안정적이므로 "진짜 변경된 것만 감지"하는 React의 최적화 철학과는 거리가 있는 것 같아 질문합니다.