리액트의 렌더링 로직에서 벗어나 즉각적으로 렌더링을 실행시키는 금쪽이 형제 forceUpdate, flushSync에 대해 정리한다.
리액트는 선언적인 컴포넌트 기반 프로그래밍을 지향한다. 개발자는 간단한 뷰만 설계하도록 유도하고 실제 화면에 뷰를 그리는 로직은 리액트 내부에서 효과적으로 처리하도록 한다.
리액트는 이를 통해 코드가 예측하기 쉬워지고, 디버깅에 유리한 장점을 지닌다고 소개한다.
효과적인 렌더링을 위한 로직 중에 해당 주제에 연관이 되는 로직은 component life cycle, auto batching 두 가지 이다.
리액트는 뷰를 효과적으로 업데이트 하기 위해서 브라우저의 DOM을 직접 조작하지 않고 virtual DOM을 생성해 변경점을 계산하고, 최종적으로 DOM을 한번만 조작해 빠른 렌더링을 제공하고자 한다.
이러한 로직 가운데 리액트는 변화가 필요한 순간에만 컴포넌트를 업데이트 할 수 있는 몇 가지 기준을 세우고, 그에 따라 사용자가 사용할 수 있는 메서드를 제공하는데 이를 lifeCycleMethod라고 부른다.
이에관한 자세한 내용은 다루지 않을 것이기에 만약 궁금하다면, react life cycle method, react vertual DOM, react fiber, react reconciliation 등을 검색해보는 것을 추천한다.
리액트에서 리렌더링이 트리거 되는 요소중 하나는 state 값의 갱신이다. 기본적으로 state가 한번 업데이트 되면 컴포넌트도 한번 리렌더링 된다. 하지만 이는 state가 자주 업데이트 될 수록 컴포넌트 또한 자주 리렌더링 되기 때문에 이는 성능적인 면에서 좋지 않다.
이러한 문제점을 해결하기 위해 리액트는 auto batching을 사용해 리렌더링 횟수를 줄인다.
auto batching은 여러 state의 업데이트들을 묶어 한번에 처리하는 식으로 리렌더링 횟수를 절감한다.
18버전 이전에서 setTimeout이나 외부 라이브러리인 경우 동작하지 않았지만 18버전 업데이트 이후로는 거의 모든 경우에 정상적으로 동작한다.
class 컴포넌트에서 사용할 수 있는 forceUpdate는 react의 lifeCycleMethod 중 render 메서드를 즉시 호출하는 메서드이다.
//...
forceUpdate()
//...
lifeCycleMethod의 호출 순서를 무시하고, 바로 render 메서드를 호출시키기 때문에 forceUpdate를 통해 리렌더링 시키면, render이전에 호출되어야 하는shouldComponentUpdate가 호출되지 않는다.
이러한 비정상적인 리렌더링은 forceUpdate가 호출된 컴포넌트에만 해당하고 그의 자식 컴포넌트들은 정삭적인 lifeCycle 흐름이 일어난다.
function 컴포넌트에서 사용할 수 있는 flushSync는 비슷한 타이밍에 변경되는 state 중 특정 state를 동기적으로 업데이트 해야만 할 때 사용할 수 있는 메서드이다.
//...
flushSync(
setState((prev)=>prev+1)
)
//...
auto batching을 무시하고 변경된 상태를 즉시 화면에 적용시키기 위해 렌더링을 일으킨다.
두 메서드 모두 기존의 흐름에서 벗어나 즉시 렌더링을 일으킨다는 공통점을 지니지만 벗어나고자 하는 기존 흐름이 다르기에 완전히 같지는 않다. 또한 이러한 직접 조작은 리액트에서 지향하는 프로그래밍이 아니기 때문에 두 메서드 모두 최대한 사용을 자제하고 기존 방식을 통해 구현하도록 권장하고 있다.
Reference
react.dev