Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[11팀 임재도] [Chapter 1-3] React, Beyond the Basics #41

Open
wants to merge 19 commits into
base: main
Choose a base branch
from

Conversation

effozen
Copy link

@effozen effozen commented Jan 2, 2025

과제 체크포인트

기본과제

  • shallowEquals 구현 완료
  • deepEquals 구현 완료
  • memo 구현 완료
  • deepMemo 구현 완료
  • useRef 구현 완료
  • useMemo 구현 완료
  • useDeepMemo 구현 완료
  • useCallback 구현 완료

심화 과제

  • 기본과제에서 작성한 hook을 이용하여 렌더링 최적화를 진행하였다.
  • Context 코드를 개선하여 렌더링을 최소화하였다.

과제 셀프회고

🧑‍💻 학습, 기록, 실험, 성장

지난 1~2 주 동안 제가 제대로 과제를 소화하고 있지 못함을 깨달았습니다.
이는 제가 원하는 성장 방향이 아니었고, 무엇이 원인일까 분석을 해봤습니다.

원인은 다음과 같았습니다.

  1. 테스트에 맞추기 급급해서 코드 자체에 대한 생각을 많이 하지 못했다.
  2. 좋은 참고 자료가 주어졌음에도 학습을 제대로 하지 못했다.
  3. 앉아있는 시간 대비 실제로 집중한 시간이 너무 적었다.
  4. 분명 봤는데, 기억이 안나고 써먹지도 못했다.

그래서, 이번에는 조금 방식을 바꿔보고자 했습니다.

제가 집중도가 가장 많이 올라갈 때는 지식이 선처럼 이어질 때 입니다.

그리고, 눈에 보이는 어떤 작은 성과가 계속 이어질 때 집중도가 가장 크게 올라감을 깨달았습니다.

이에, 학습할때는 손으로 기록하든, 블로그에 적든 눈에 보이는 요소로 남겨두기로 했습니다.

또한, 그렇게 학습이 끝나면 반드시 블로그로 정리하기로 했습니다.
그냥 지식을 나열하는 것이 아닌 제가 스스로 실습을 하거나, 고찰한 내용을 바탕으로 한 글을 적기로 했습니다.

실제로 글을 눈으로만 읽는 것보다 손으로 따라 치고, 그걸 블로그에 나만의 용어로 적는 과정에서, 제가 모르는 부분이 많이 보였습니다.
그 부족한걸 채우면서 적다보니 "4. 분명 봤는데, 기억이 안나고 써먹지도 못했다." 문제를 해결할 수 있었습니다.

재밌게도, 글이 하나씩 완성되어 갈 수록 1, 2, 3 모두가 같이 해결이 되었습니다.

그래서 무려 3주가 걸렸지만.. 이제야 조금 어떻게 항해를 활용할 지 감이 온 듯 합니다.

기술적 성장

🧑‍💻 나의 용어로 풀어보기

과제에 관련되어서 제 스스로가 구멍이라고 생각되는 부분을 정리하기로 했습니다.

그리고 다음과 같은 정리글이 나왔습니다.

리액트 훅이란?

리액트 개발자 도구 탐구

해보면서 느낀 리액트 성능 최적화에 대한 고찰

훅을 제대로 몰랐는데 이를 통해 알게 되었습니다.

console.log로 찍어가면서 개발을 진행하였는데, 이를 해결할 수 있었습니다.

위의 두개를 바탕으로 성능 최적화를 고민해볼 수 있게 되었습니다.

코드 품질

만족스러운 부분은 부족할지라도, 나름대로 모듈화도 해보고 useCallback, useMemo, React.memo 등을 적용해보면서 성능 최적화 기법을 도입해봤다는 점이 만족스럽습니다.

그리고, 베럴파일, 타입 분리, contexts 분리, hooks 분리 등을 통해서 저 만의 디렉토리 분류 기준을 잡은 것이 만족스럽습니다.

실제로 1주차에 제가 가진 고민이 이 디렉토리 분리였기에 감을 잡고 적용했다는 게 굉장히 뿌듯한 것 같습니다.

다만, 여전히 코드는 엉성한 점이 많은 것 같습니다.

특히, 에러가 발생하기 시작하면 해결하기 위해서 이것 저것 시도하다보니.. 엉망이 되는 경우가 있는 것 같습니다.

또한 최근, intelliJ에서 vscodeIDE를 옮겼는데, 이 과정에서 설정이 잘못되었는지.. ,나 몇몇 규칙들이 IDE 차원에서 수정이 되고 있습니다. 이에 따라, 린트와 충돌되는 부분이 생기고 에러도 발생해서 이런 부분 때문에 좀 더 엉망이 된 부분이 없지 않아 있는 것 같습니다.

제가 생각하기에 다음의 요소에 대한 리팩토링은 꼭 해볼까합니다.

  1. 컴포넌트를 큰 단위로만 나눴는데, <li> 등 작은 컴포넌트도 분리해야 한다.
  2. 참조형 데이터가 의존성 배열로 들어가있다. 이를 좀 더 잘 풀어낼 방법이 있을 것 같다.
  3. React.memo를 모든 컴포넌트에 넣었는데, 이로 인해서 성능 저하가 발생하기도 했다. 조금 더 판단의 기준을 갖고 적용해야 한다.

특히 3번은 최적화 기준에 대한 부분이기에 계속해서 고민해가면서 저만의 기준을 세워야할 부분 같습니다.

학습 효과 분석

지난 3주를 통틀어서 이번에 제가 제일 과제를 잘 활용한 주가 아닐까 싶습니다.

  1. 주어진 학습 자료를 바탕으로 스스로가 가진 오개념 및 부족한 지식을 채웠다.
  2. 단순 텍스트 및 개념이 아니라, 실제 코드나 내가 직접 도구를 사용하면서 그걸 바탕으로 나만의 언어로 정리해냈다. 이 과정에서 한번 더 내가 잘못 이해하고 있거나, 애매하게 안 개념을 채울 수 있었다.
  3. 코드 작성 능력이 많이 부족해서 빠르게 작성하는 것을 모토로 두되, 각 과정을 명확하게 근거를 세우는 것을 목표로 했는데 블로그 글을 쓰면서 한 덕분인지 이 목표를 달성할 수 있었다.

이런 관점에서 정말 고무적인 한주 였던 것 같습니다.

과제 피드백

전체적으로 과제 내용이 너무 좋았습니다.

특히, 훅이 뭔지 이해 -> 훅을 구현 -> 최적화 까지 이어지는 일련의 흐름이 너무 좋았습니다.

1~3주를 돌아보았을 때 SPA -> VDOM 기반 렌더링 -> 훅 -> 최적화까지 리액트 전반을 다 훑을 수 있어서 너무 좋았습니다.

굳이 아쉬운점을 꼽자면, 이번주에 자주 언급된 husky 설정이 조금 아쉬운 것 같습니다.

리뷰 받고 싶은 내용

1. 성장의 요인으로 기록을 활용하려고 하고 있습니다. 다만, 어느 정도는 취업이나 자기 PR도 염두에 두고 있습니다. 제가 쓴 글이 과연 후킹이 되는 관심을 끌만한 글인지, 개발자 관점에서 "도움이 되는" 좋은 글인지 궁금합니다.

리액트 훅이란?

리액트 개발자 도구 탐구

해보면서 느낀 리액트 성능 최적화에 대한 고찰

2. 리액트 개발자 도구를 통한 성능 측정을 맞게 해석한건지 여쭙고 싶습니다.

최적화 기법 도입 전 최적화 기법 도입 후
1 2

다크모드/라이트모드 전환 시 위와 같이 성능 측정이 이루어졌는데 저는 이걸 개선되었다고 생각하였습니다.

  1. Render duration이 감소한 것.
  2. Committed at이 증가했지만 그럼에도 Render duration + Committed at이 감소한 것.

그래서 성능이 개선되었다고 생각했는데, 나온 통계를 맞게 해석한 건지 궁금합니다.

3. 리액트 최적화 기법을 맞게 사용한 건지 궁금합니다.

최적화 기법 도입 전 최적화 기법 도입 후
before_flame_bad after_flame_bad

로그인/로그아웃 시 위와 같은 수치를 보였습니다. 2번의 판단 기준대로라면, 오히려 성능이 저하가 된 요소입니다.

최적화 기법을 "잘" 쓰면 성능이 개선된다고 했는데, 제가 짠 코드에서는 성능이 개선된 부분도 있고, 개선되지 않은 부분도 있는 것 같습니다.

왜 이럴까 고민을 했는데...

useCallback으로 함수의 동등성을 보장함과 동시에 중복 선언을 막고, useMemo로 값을 반환하기 위한 쓸데없는 연산을 막았습니다.

지식이 부족한 탓에, 여기에는 문제가 없게 느껴집니다. 문제가 있다면 모든 컴포넌트 마다 걸어준 React.memo 인 듯 한데.. 이와 관련해서 왜 이런 이슈가 발생한지.. 여쭙고 싶습니다.

다소 아둔한 질문이지만.. 정말 지식이 부족해서.. 쉽게 감을 잡지 못해 여쭙습니다.

@effozen effozen changed the title [WIP][11팀 임재도] [Chapter 1-3] React, Beyond the Basics [11팀 임재도] [Chapter 1-3] React, Beyond the Basics Jan 2, 2025
Copy link

@wonjung-jang wonjung-jang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 Context를 만들 때 데이터와 업데이트 함수를 별도의 Context로 만들다보니 파일에 내용이 많아져서 분리할까 고민하다가, 그냥 한 곳에 몰아넣는 방법으로 했는데 재도님이 분리하신 거 보니 깔끔해서 분리할 걸 그랬나는 생각이 드네요!👍

Comment on lines +6 to +13
if (
typeof objA !== "object" ||
objA === null ||
typeof objB !== "object" ||
objB === null
) {
return objA === objB;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 기본형 데이터를 한 번에 처리하신 것 같은데 이렇게 합칠 수도 있군요!👍

Comment on lines +29 to +30
!Object.prototype.hasOwnProperty.call(objB, key) ||
objA[key] !== objB[key]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이렇게 사용하면 타입 오류나지 않나요??

Comment on lines +15 to +47
// 2. 둘 다 객체인 경우:
// - 배열인지 확인
// - 객체의 키 개수가 다른 경우 처리
// - 재귀적으로 각 속성에 대해 deepEquals 호출
if (Array.isArray(objA) && Array.isArray(objB)) {
if (objA.length !== objB.length) {
return false;
}

for (let i = 0; i < objA.length; i++) {
if (!deepEquals(objA[i], objB[i])) {
return false;
}
}
} else {
// 두 객체의 키 개수가 다른 경우
const keysA = Object.keys(objA) as (keyof T)[];
const keysB = Object.keys(objB) as (keyof T)[];

if (keysA.length !== keysB.length) {
return false;
}

for (const key of keysA) {
if (
// general하게 사용되는 deepEquals이므로, Object.prototype.hasOwnProperty를 사용 (call로 매핑해줌으로써, 예외상황을 처리)
!Object.prototype.hasOwnProperty.call(objB, key) ||
!deepEquals(objA[key], objB[key])
) {
return false;
}
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shallowEquals랑 다르게 배열을 별도로 처리하신 이유가 궁금합니다!

<div
className={`min-h-screen ${theme === "light" ? "bg-gray-100" : "bg-gray-900 text-white"}`}
>
const MainApp: React.FC<MainAppProps> = React.memo(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

App에서 propsitemsonAddItemsClick을 받아서 React.memo를 해주신 것 같은데, MainApp으로 itemsonAddItemsClick을 옮겨도 됐을 것 같은데, App에서 props로 할당받게 한 이유가 있으신가요?

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.

2 participants