Skip to content

[10팀 오유진] Chapter 1-3 React, Beyond the Basics #65

Open
YoojinOhDev wants to merge 13 commits into
hanghae-plus:mainfrom
YoojinOhDev:main
Open

[10팀 오유진] Chapter 1-3 React, Beyond the Basics #65
YoojinOhDev wants to merge 13 commits into
hanghae-plus:mainfrom
YoojinOhDev:main

Conversation

@YoojinOhDev
Copy link
Copy Markdown

@YoojinOhDev YoojinOhDev commented Apr 10, 2025

과제 체크포인트

배포 링크

https://front-5th-chapter1-3-rust.vercel.app/

기본과제

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

심화 과제

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

과제 셀프회고

기술적 성장

[📌 useContext]

회사에서 업무를 할때 contextAPI 를 잘 사용하지 않았기에 개념을 작 학습하고 과제에 적용해볼 수 있었다. 이번 주 회사 업무를 하면서 한 페이지 곳곳에서 사용되는 값이 있어 context를 적용해보기도 했다.

한 가지 또 중요하게 배운 것은 context 값의 변경이 리렌더링을 유발한다는 것이었다. 컴포넌트의 리렌더링을 발생시키는 조건으로 아래 조건만 알고 있었는데

1. 부모 컴포넌트의 리렌더링
2. 컴포넌트 key값의 변경
3. props값의 변경 
4. state 변경 

한 가지 조건을 더 알게 되었다.

5. 🔥 useContext()로 구독하고 있는 context의 값의 변경🔥 

과제를 진행하면서 하나로 모인 AppContext를 관심사에 따라 분리만 하고, Provider를 나누기만 했는데도 몇 가지 테스트 코드가 추가로 통과된 것이 의아했는데, 위 내용을 알고 나니 그 이유를 이해할 수 있었다.

[📌 useState의 지연 초기화]

과제를 하면서 ItemList가 여러번 리렌더링될때 계속해서 generateItems 함수가 호출되는 이유를 찾아보았고, useState 초깃값으로 사용한 generateItems가 모든 렌더링마다 계속해서 호출된다는 것을 발견하게 되었다. 예전에 ‘useState의 초깃값에 함수를 넣는 것과 값을 넣는 것 사이에 차이가 있다’ 를 어디선가 들은 기억 덕분에 함수 자체를 호출하는 방식으로 바꾸고 테스트 코드가 통과하게 되었다.

이와 관련하여 React 공식 문서에서 useState 관련 부분을 다시 찾아보면서 지연초기화 방식에 대해 정확하게 이해할 수 있었다.

[ useState 매개변수 initialState 의 특징]

  • initialState의 값은 최초 렌더링에서만 사용된다
  • initialState가 함수인 경우
    • 이 함수는 순수해야 하고
    • 인자를 받지 않아야 하고
    • 반환값이 존재해야한다

리액트 컴포넌트는 모든 렌더링에서 전체 함수 본문을 다시 실행시키기 때문에, initialState 로 함수를 ‘호출’하게 되면 그 값은 리렌더링시에서 사용되지는 않지만, 함수 호출 자체는 계속된다.

공식문서에서는 이에 대해 ‘큰 배열을 생성하거나 값비싼 계산을 수행하는 경우 낭비일 수 있습니다.’ 라고 말하고 있는데
정확히 이에 대한 예제가 이번 과제 코드에 포함되어있었다

const [items, setItems] = useState(generateItems(1000));

위 코드에서는 모든 렌더링 단계마다 generateItems 함수가 실행된다. 이 함수는 원소가 1000개인 배열을 생성하고 순회한다. 공식문서에서 말하는 정확한 ‘ 큰 배열을 생성’ 하는 케이스이다.

어차피 초기값은 최초 렌더링에만 사용되기 때문에 매 렌더링 단계마다 이 함수가 실행되어야 한다면 성능 낭비이다. 이런 경우 리액트는 아래와 같은 방식을 통해 지연 초기화(lazy initialization)을 제안한다.

const [items, setItems] = useState(() => generateItems(1000));

useState의 initialState에 함수 자체가 사용되는 경우, React는 초기화, 즉 최초 렌더링 중에만 함수를 호출하기 때문에 성능을 향상시킬 수 있다.

지연초기화가 동작하는 방식에 대해 조금 더 찾아보고 아래와 같은 방식으로 이해할 수 있었다.

💡 컴포넌트의 useState는 ‘모든’ 렌더링마다 아래와 같은 순서로 작동된다.

1. initialState 의 값을 전달
2. 내부적으로 초기화가 되었는지 확인
    2-1. 초기화가 안되어있다면 (최초 렌더링이라면) 초기화 진행
    2-2. 초기화가 되어있다면 (리렌더링이라면) 초기화를 하지 않음

이때 1번 과정에서 'initialState의 값'이 중요하다.

useState(함수()) 에서는 initialState의 값을 얻기 위해 이 함수를 실행하고 반환 값을 얻는다. 즉 항상 함수 실행이 일어난다.

반면 useState(()=> 함수()) 에서는 함수 그 자체 (아마도 참조값)가 initialState의 값이다. 함수가 실행할 필요가 없다. 이 함수는 2-1 케이스에 해당할때만 (즉 최초 렌더링일때만) 실행된다.

위와 같은 이유로 useState 내에 함수 자체를 넣는 경우, 특히 이 함수가 큰 계산을 해야 하는 경우 성능을 향상시킬 수 있다

코드 품질

App.js 에 모여있던 각종 컴포넌트들과 context를 별도의 파일로 분리한 부분은 잘했다고 생각한다.

다만 App.js 내에서 useTheme 을 사용하기 위해서 아래와 같이 모든 내용을 MainContent로 분리하고

const App: React.FC = () => {
  return (
    <ThemeProvider>
      <MainContent />
    </ThemeProvider>
  );
};

export default App;

MainContent 내에서
const { theme } = useThemeContext(); 를 사용했는데, 이게 좋은 구조인지는 잘 모르겠다..!

학습 효과 분석

기술적 성장 파트에서 적은 내용이긴 하지만, context의 경우 이번 과제를 통해서 처음 사용하게 되었고, 이번주에 작업하던 실무 작업에도 활용해볼 수 있어서 좋았다.

useState의 경우 지연초기화 자체가 필요한 경우가 자주 있지는 않겠지만, 지연초기화가 일어나는 방식을 이해하게 된 것이 좋았고, 옛날에 어디에선가 주워들었던 내용이 과제 해결에 큰 key가 되었어서.. 아는 것은 어떻게든 도움이 된다는 사실을 한번 더 체감하게 되었다..!

useRef, useMemo, useCallback 등에 대해서도 내부 동작을 모사해보니 동작 원리를 훨씬 더 잘 이해하게 되었다. 특히 memo의 경우 공식문서를 읽었을 때 공식문서 예제를 보고

const MemoizedComponent = memo(SomeComponent, arePropsEqual?) 

arePropsEqual 가 무슨 의미인지 당최 이해하기가 어려웠는데, 이번 과제에서 직접 memo를 모사해보니, 이 인자가 어떤 의미이고 어떤 역할을 하는지 훨씬 더 명확하게 이해할 수 있었다.

과제 피드백

과제를 직접 해보기 전까지는 각종 hook들을 직접 만들어보는 게 리액트 작동 원리를 이해하는데 얼마나 도움이 될 수 있을지 잘 와닿지 않앗는데, 직접 해보니 도움이 정말 많이 된다고 느꼈다.

그리고 과제 테스트 코드들을 보면서 좋은 테스트 코드가 있다는게 개발할 때 얼마나 든든한 울타리 같은 역할을 해보는지 느끼게 되었다. 그리고 발제 자료의 테스트 코드를 보니, 내가 쓰던 테스트코드는 아주 기초중의 기초 수준이었다는 것을 깨닫고 있다..!

리뷰 받고 싶은 내용

멘토링때 이미 궁금했던 내용들을 너무 잘 설명해주셔서 리뷰를 받고 싶은 구체적인 내용은 이번 주차에는 더 생각나는 부분은 없었고, 공부를 하면서 생긴 궁금증들이 있어서 이 부분에 대한 질문을남겨봅니다!

잘 알고 있어야 하는 기술들, 예를 들어 react, nextJS, javascript와 같은 언어와 프레임워크 뿐 아니라 react-hook-form, tanstack-query, zod 등 자주 사용되는 라이브러리들에 대해서도 학습의 필요성을 언제나 느끼는데요..! (정말 공부에 끝이 보이지 않는 것 같습니다 ㅎㅎ;;)

학습을 하려고 공식문서를 보면, 내용이 너무 방대하여 어디부터 봐야할지, 얼마나 깊이 봐야할지도 잘 모르겠고 읽어보더라도 한번에 잘 이해가 가지 않습니다..!

코치님의 경우 새로운 기술을 공부하시는 팁이 있으신지, 어느 정도의 경지(?)에 이르러야 새로운 기술을 학습하는 한계 비용이 줄어들기 시작할 지 코치님의 경험이 궁금합니다!

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