반응 일괄 업데이트

단일 렌더 호출에서 상태 업데이트를 결합하는 방법

React.js 일괄 업데이트

구성 요소의 상태를 업데이트할 때마다 React의 diffing 알고리즘이 가상 DOM의 변경 사항을 감지하고 구성 요소를 실제 DOM에 렌더링한다는 것을 이미 알고 있습니다. 그러나 이것이 모든 단일 상태 업데이트에 대해 실제로 발생합니까? 아니면 React가 이러한 업데이트를 일괄 처리하는 방법을 제공하여 여러 상태 변형이 단일 렌더 호출로 결합되도록 합니까?

합성 이벤트는 일괄 업데이트를 허용합니다.

React 17 이하에서는 이러한 업데이트를 일괄 처리하는 메커니즘을 제공합니다. 코딩하는 동안 실제로 그것에 대해 많이 생각할 필요는 없지만 React가 코드를 최적화하는 방법을 아는 것은 그럼에도 불구하고 훌륭한 학습입니다.

여기에 무슨 일이 일어나고 있습니다.

  • 콜백 내에서 여러 상태 돌연변이가 호출됩니다.
  • 콜백이 합성 이벤트에 연결되면 React는 해당 돌연변이를 일괄 처리합니다.
  • 돌연변이가 일괄 처리되면 단일 렌더 호출만 수행됩니다.
  • 그렇지 않으면 각 돌연변이가 새로운 렌더링으로 이어집니다.

일괄 처리를 허용하려면 합성 React 이벤트 내에서 상태 돌연변이를 호출해야 합니다. 빠른 알림으로, 합성 React 이벤트는 기본적으로 모든 브라우저에서 동일한 기능을 제공하는 기본 HTML 이벤트에 대한 래퍼입니다. 모든 합성 이벤트 핸들러는 prop으로 컴포넌트에 직접 제공될 수 있습니다.

모든 동작을 확인하기 위해 React가 돌연변이당 하나의 렌더링 대신 모든 상태 돌연변이를 단일 렌더링으로 결합할 수 있는 예제 코드가 있습니다.

function Component() {
  const [id, setId] = useState(0);
  const [date, setDate] = useState(new Date());
  const [random, setRandom] = useState(Math.random());

  // A lame callback, but it's just for
  // the demo. Note that clicking on the
  // button will only lead to a single
  // re-render!
  //
  // This is b/c the callback is provided to
  // 'onClick', a synthetic event.
  const onButtonClick = () => {
    setDate(new Date());
    setId(prevId => prevId + 1);
  }
  
  console.log("Render:", id, date);

  return (
    <div>
      <button 
        onClick={onButtonClick}>
        Update state
      </button>
    </div>
  );
}
//
// Almost the same as the previous
// example, but this time w/o
// a batched upate call.
//

function Component() {
  const [id, setId] = useState(0);
  const [date, setDate] = useState(new Date());
  const [random, setRandom] = useState(Math.random());

  // No batching, as the state
  // mutations happend inside
  // a setTimeout - even though
  // the timeout is inside a 
  // synthetic event.
  const onButtonClick = () => {
    setTimeout(() => {
      setDate(new Date());
      setId(prevId => prevId + 1);
    }, 0);
  }
  
  console.log("Render:", id, date);

  return (
    <div>
      <button 
        onClick={onButtonClick}>
        Update state
      </button>
    </div>
  );
}

React 18 이상에 대한 일괄 업데이트

다음 버전의 React에서는(적어도 이 글을 쓰는 동안) 일괄 처리 메커니즘이 훨씬 더 개선될 것입니다. 합성 이벤트에서만 가능한 대신 다른 유형의 콜백도 사용할 수 있습니다.

  • 시간 초과
  • 약속
  • 네이티브 이벤트 핸들러

이 변경으로 인해 자동으로 수행되는 렌더링이 줄어들기 때문에 앱의 성능이 향상될 가능성이 큽니다.

React 18 이상에서 일괄 업데이트 피하기

React 18부터는 각 상태 변형으로 새 렌더링을 명시적으로 트리거하는 옵션이 있으므로 일괄 업데이트를 피할 수 있습니다. 이것은 거의 예외적인 경우에만 사용되지만 그럼에도 불구하고 아는 것은 흥미로울 것입니다.

//  
// This example is almost
// 1:1 from Dan Abramov's
// example.
//
// Use 'flushSync' from the
// 'react-dom'-package.
import { flushSync } from 'react-dom'; 

function handleClick() {
  flushSync(() => {
    setId(prevId => prevId + 1);
  });
  // React has updated the DOM by now
  flushSync(() => {
    setDate(new Date());
  });
  // React has updated the DOM by now
}