학습을 목적으로 Medium에서 읽은 글을 번역한 글입니다.
번역이 완벽하지 않을 수 있고,
직역하기보다는 문맥에 맞추어 자연스럽게 정리하려고 했습니다.
오류나, 개선하면 좋을 부분들에 대한 피드백은 언제나 환영합니다.😁
React State Batch Update
함수형과 클래스형 컴포넌트 모두 state를 변경하고 구성하는 방법은 몇 가지가 있다.
우리는 setState 혹은 useState를 사용하여 state를 변경한다.
이러한 방법으로 state값을 변경함으로써 일부 컴포넌트와 그 자식 컴포넌트들에게 re-render가 일어나도록 만들 수 있다.
많이 언급되진 않지만, 리액트의 흥미로운 메카니즘중 하나는 batch updating이다.
리액트는 업데이트되야 할 항목을 각각 업데이트하는 대신 batch update(일괄 업데이트)를 통해 컴포넌트의 렌더링 횟수를 최소화한다.
이 글에서는 예제를 사용하여 언제, 그리고 어떻게 batch update가 일어나는지 알아보려고 한다.
클래스형 컴포넌트 state
클래스형 컴포넌트는 this.setState를 통해서만 state의 값을 업데이트할 수 있는 하나의 state 객체가 존재한다.
import React from "react";
export default class Component extends React.Component {
state = {
counter1: 0,
counter2: 0,
counter3: 0,
}
handleClick = () => {
this.setState((state) => {
return {
counter1: state.counter1 + 1,
counter2: state.counter2 + 1,
counter3: state.counter3 + 1
}
})
}
render() {
return (
<div>
<div>Counter1: {this.state.counter1}</div>
<div>Counter2: {this.state.counter2}</div>
<div>Counter3: {this.state.counter3}</div>
<button onClick={this.handleClick}> Click Me!</button>
</div>
);
}
}
Hooks state
hooks를 사용하게 된다면 몇가지의 방법을 통해 컴포넌트의 state를 구성할 수 있다.
- 클래스형 컴포넌트와 같이 하나의 state객체내에서 여러 사용한다.
- 하나의 state객체는 하나의 값을 지정할 수 있도록 각각 나눈다.
- 관련된 state끼리 나눈다.
//1
import React, { useState } from "react";
export default function Component() {
const [state, setState] = useState({
age: 10,
name: 'John',
text: 'some text'
});
return (
<div>
<div>User - name: {state.name}, age: {state.age}</div>
<div>Text: {state.text}</div>
</div>
);
}
//2
import React, { useState } from "react";
export default function App() {
const [age, setAge] = useState(10);
const [name, setName] = useState('John');
const [text, setText] = useState('some text');
return (
<div>
<div>User - name: {name}, age: {age}</div>
<div>Text: {text}</div>
</div>
);
}
//3
import React, { useState } from "react";
export default function App() {
const [user, setUser] = useState({
age: 10,
name: 'John'
});
const [text, setText] = useState('some text');
return (
<div>
<div>User - name: {user.name}, age: {user.age}</div>
<div>Text: {text}</div>
</div>
);
}
클래스형 컴포넌트에서 hooks를 적용하여 리펙토링을 진행할 경우
리액트 16.8에서 hooks가 공개된 이후 리액트 커뮤니티에서는 예전 방식인 클래스형 컴포넌트와의 열띤 논쟁이 벌어졌었다.
클래스형 컴포넌트를 hooks가 적용된 함수형 컴포넌트로 리펙토링할 때 고려해야 할 사항이 여러 가지 존재하는데 그중 한 가지는 state를 구성하는 방법이다.
hooks와 관련하여 리액트 공식문서에 따르면
'함께 변경되는 값에 따라 state를 여러 state변수로 분할하는 것을 추천합니다.' 라고 한다.
최근 직장동료가 나에게 어떻게 클래스형 컴포넌트를 hooks를 적용한 함수형 컴포넌트로 올바르게 마이그레이션하는지, 또한 새로운 state를 어떻게 나누어야 하는지에 대해 물어보았다.
나의 첫번째 대답은 위에 나와있는 리액트 공식문서에서 권장하는 방법이었다. 하지만 나는 이 대답이 마음에 들지 않았다.
어떠한 state값이 함께 변하는 값인지 어떻게 미리 알고 있으며, 또한 나중에 추가될 기능에 의해 묶어놓은 state를 분리해야 할 경우도 생길 것이다.
그래서 결국 나는 그에게 state값을 각각 독립적인 변수로 나누라고 제안했다.
그의 (당연히 나올법한) 다음 질문은 '만약 state값을 각각의 이산변수로써 나누게 되면 우리는 각 state값을 하나하나 바꿔줘야 할 것이고, 그렇게 되면 불필요한 re-render가 너무 많이 일어나게 되어서 어플리케이션의 성능에 영향을 미치지 않을까요?'였다.
React batch updating
'리액트는 성능을 위해 여러 setState()를 단일 업데이트(batch update)로 한꺼번에 처리할 수 있습니다.'
- 리액트 공식문서
batch updating은 state의 업데이트를 결합하는 리액트의 흥미로운 기능이다.
batch update기능의 주된 아이디어는 리액트의 이벤트 핸들러와 생명주기 메서드를 사용하여 얼마나 많은 setState를 호출하든 간에
단 하나의 업데이트로 일괄 처리하여, re-render가 한 번만 발생하도록 하는 것이다.
이 기능은 불필요한 렌더링을 방지하기 위한 목적이고, 함수형 컴포넌트와 클래스형 컴포넌트 모두 연관되어 있다.
현재는(리액트 16 및 이전 버전) 리액트 이벤트 핸들러의 업데이트에만 기본적으로 batch update가 적용된다. - Dan Abramov
Batch update 예시
다음의 예시를 보자
버튼을 클릭하면 컴포넌트 내의 세 개의 독립적인 state값이 차례대로 변경되는 함수형 컴포넌트이다.
예상과는 반대로 클릭을 하게 되면 세개의 state값이 각자 변경되지만 컴포넌트는 한 번의 렌더링이 일어나게 된다.
이는 batch update기능 덕에 가능한 부분이다.
함수형 컴포넌트
클래스형 컴포넌트
어떤 상황에서 batch updating이 적용될까?
위에서 언급했듯이, batch update는 이벤트 핸들러 내에서 일어난다. 하지만 실제로는 다른 메서드에서 동작하기도 한다.
이번 예에서는 batch update가 useEffect에서 어떻게 작동하는지 보려고 한다.
클래스형 컴포넌트에서는 setState가 componentDidMount메서드 내에서 호출되었기에 세 번이 아닌 한 번만 업데이트가 일어나는 것을 확인할 수 있다.
하지만 모든 상황에서 똑같이 batch update가 일어나지는 않는다.
모든 상황에서 리액트가 batch update의 기능을 실행하는 것은 아니다.
이벤트 핸들러가 비동기 처리 방식으로 실행될 경우, 예를 들면 async/await, then/catch, setTimeout, fetch 등, 각각의 독립된 state값의 update는 일괄적으로 처리되지 않을 것이다.
강제로 batch update를 적용하는 방법
이런 경우 다행히, ReactDOM.unstable_batchUpdate를 사용함으로써 batch update가 가지는 장점을 필요할 때 이용하여 문제를 극복할 수 있다.
아래는 ReactDOM.unstable_batchUpdate를 활용한 예시이다.
ReactDOM.unstable_batchUpdate가 불안정한 함수이긴 하지만 리액트는 다음 버전에서 이러한 문제를 해결하려고 할 것이다.
앞으로의 버전에서(아마도 리액트 17 혹은 그 후의) 리액트는 기본으로 모든 업데이트를 일괄적으로 처리할 것이다. 그러니 앞으로는 이것에 대해 따로 고민하지 않아도 된다.
- Dan Abramov
결론
리액트 훅과 클래스형 컴포넌트를 사용하는 두 경우 모두, batch update와 같은 기능이 존재한다는 것을 아는 것은 state값을 다루기에도, 성능적인 면에서 관리하기도 좀 더 쉽게 만들어준다.
이번 글이 더 효율적이고 깔끔하게 state를 업데이트하는 방법을 이해하는데 도움이 되길 바랍니다.
원문
https://medium.com/swlh/react-state-batch-update-b1b61bd28cd2
'개발 > Medium' 카테고리의 다른 글
TIR ##5 [How To Study Design Patterns as a Web Developer] (0) | 2022.03.30 |
---|---|
TIR ##4 [Why All React Developers Should Try Next.js] (0) | 2021.09.13 |
TIR ##3 [Async Nature of Javascript] (0) | 2021.09.09 |
TIR ##2 [What You Need to Know About React 18] (0) | 2021.07.09 |