이번 스프린트를 마치기 전 데모를 해보다가 화면상 표시되는 데이터가 실제 데이터와 다르다는 사실을 발견했다.
원인을 찾아보니 동료 개발자가 의도치 않게 자료형에 Mutation을 일으켜 잘못된 데이터가 표시된 것이었다.
그리고 Mutation이 발생한 이유는 2회 컴포넌트가 렌더링 되면서 함수가 두 번 실행되었기 때문이라는 사실도 알게 되었다.
사실 이전 부터 궁금하긴 했었다. useState 혹은 useEffect를 사용한 컴포넌트에서 콘솔을 찍으면 항상 두 번 프린트되었기 때문이다. 그래서 오늘은 관련해서 왜 그런지 찾아보았고 재밌는 글을 발견해 번역해 옮겨 본다.
My React components render twice and drive me crazy
# Example with a function component
새로운 CRA 설치를 우선 하자:
npx create-react-app my-app && cd my-app
function App() {
console.log('I render 😁');
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
</header>
</div>
);
}

# Example with a function component with state
하지만 함수형 컴포넌트에 이렉트 훅을 사용해 상태관리를 한다면 어떻게 될까?
function App() {
const [clicks, setClicks] = React.useState(0);
console.log('I render 😁');
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<button onClick={() => setClicks(clicks => clicks + 1)}>
Clicks: {clicks}
</button>
</header>
</div>
);
}
성공했다!! 첫번째 로딩에서 두 번 렌더링 되었고 매번 클릭할 때마다 두 번 콘솔이 찍힌다.
# Example with a function component with state in production
yarn build && npx serve build -l 3000
# Why this is happening?
위에서 언급했듯 이러한 현상은 React.StrictMode 때문이다. src/index.js 파일을 살펴보면 <App /> 컴포넌트가 아래와 같이 래핑 되어 있는 것을 확인할 수 있다.
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
# What is React.StrictMode?
React.StrictMode는 2018년에 16.3.0 버전에서 소개되었다. 처음에는 클래스 컴포넌트에만 적용가능 했지만 16.8.0 이후로는 훅에서도 이용 가능해졌다.
배포 노트에 의하면:
React.Strict Mode는 어플의 비동기적 렌더링 준비를 도와주는 wrapper이다.
따라서 이것의 목적은 엔지니어가 흔히 빠질 수 있는 함정을 피하도록 돕고 레거시 API를 점차적으로 드랍시켜 리엑트 어플의 업그레이드를 돕는 데 있다.
라이브러리가 비동기적 렌더링의 시대로 나아가는 상황에서 많은 변화가 일어나기 때문에 이런 힌트는 디버깅에 아주 큰 도움이 된다. 유용하지 않은가?
# Why the double rendering then?
React.StrictMode의 사용으로부터 얻을 수 있는 장점으로는 렌더단계의 라이프사이클에서 예상치 못했던 사이드 이펙트를 발견하는데 도움을 준다.
라이프 사이클로는:
- constructor
- componentWillMount (or UNSAFE_componentWillMount)
- componentWillReceiveProps (or UNSAFE_componentWillReceiveProps)
- componentWillUpdate (or UNSAFE_componentWillUpdate)
- getDerivedStateFromProps
- shouldComponentUpdate
- render
- setState updater functions (the first argument)
위 모든 메소드들이 두 번 이상 호출된다. 따라서 내부에 사이드 이펙트가 없도록 하는 것이 중요하다. 만약에 이러한 원칙을 무시한다면 일정하지 않은 상태 문제와 메모리 누수를 겪게 될 것이다.
React.StrictMode는 사이드 이펙트를 단번에 찾아낼 수는 없지만 몇몇 중요한 함수를 고의로 두 번 실행시켜 이를 찾기 쉽도록 해준다.
그러한 함수로는:
- Calss component constructor, render, shouldComponentUpdate 메소드
- Class component static getDerivedStateFromProps 메소드
- Function component bodies
- State updater functions (the first argument to setState)
- Functions passed to useState, useMemo, 혹은 useReducer
리-렌더링은 분명히 성능에 영향을 미친다. 하지남 이는 개발환경에서만 발생하고 프로덕션에서는 발생하지 않으니 걱정하지 말라.
출처: https://mariosfakiolas.com/blog/my-react-components-render-twice-and-drive-me-crazy/
My React components render twice and drive me crazy
Many frontend developers who use modern React, wonder why their components render twice during development but this is actually happening for a good reason.
mariosfakiolas.com
'Front-End > React' 카테고리의 다른 글
[React] 커스텀 훅 이용하기 (0) | 2022.10.19 |
---|---|
[React] Build 후에 CSS 사라짐 현상? (0) | 2022.08.14 |
[React] 리엑트 디자인 패턴: Return Component From Hooks (0) | 2022.06.30 |
[React] 2022 리엑트 컴포넌트 디자인 패턴 (0) | 2022.06.30 |
[React] Controlled vs Uncontrolled component (0) | 2022.06.21 |