백그라운드에서 리액트가 작동하는 방식

zimablue·2023년 8월 21일

react

목록 보기
5/14

리액트 DOM

리액트의 역할은 가상 DOM이라는 개념을 사용하는 것이녀, 가상 DOM은 브라우저의 일부인 실제 DOM에 대한 작업을 합니다.

props, state 또는 context가 변경이 되면 이를 가지고 있는 컴포넌트가 변경되고, 리액트는 화면에 새로운 것을 표시하는지에 대해 확인합니다.
확인이 되면 리액트는 가상 DOM에 정보를 전달하고, 가상 DOM은 사용자가 보고 있는 화면에 새로운 것을 표시하는 역할을 합니다.

중요한 것은 컴포넌트 함수가 재실행되어 재평가하는 것이 DOM을 다시 랜더링하는 것은 아님을 알아야합니다.
실제 DOM은 리액트가 구성한 컴포넌트의 이전 상태와 트리, 그리고 현재의 상태간의 차이점을 기반으로 변경이 필요할 때만 업데이트됩니다.


이전 재평가 결과

<div>
  <h1>Hello</h1>
</div>

현재 재평과 결과

<div>
  <h1>Hello</h1>
  <p>World</p> <!-- 가상 DOM으로 재평가 후에 두 스냅샷 간의 차이만 실제 DOM에 업데이트 -->
</div>

리액트는 두 스냅샷 간의 차이점을 확인하고 가상 DOM에 보고하면 가상 DOM은 전체 DOM을 재렌더링하지 않고, 가상 DOM과 일치하도록 새로운 문장만 집어넣어 실제 DOM을 업데이트합니다.

이전과 현재의 상태를 가상으로 비교한는 것은 메모리 안에서만 발생하기 때문에, 실제 DOM을 사용하여 브라우저에 직접 렌더링하는 것에 비해 간편하고, 자원도 적게 듭니다.



개발자 도구 확인

아래의 코드에서 button을 클릭하면 <p>This is new!</p> 단락이 랜더링 됩니다.
button을 한번 더 클릭하면 <p>This is new!</p> 단락이 사라집니다.
변화가 있는 과정에서 모든 DOM이 새로 렌더링 되지 않는 다는 것을 크롬의 개발자 도구에서 확인할 수 있습니다.

function App() {
  const [showParagraph, setShowParagraph] = useState(false);

  const toggleParagraphHandler = () => {
    setShowParagraph((prevShowParagraph) => !prevShowParagraph);
  };
  return (
    <div className="app">
      <h1>Hi there!</h1>
      {showParagraph && <p>This is new!</p>}
      <Button onClick={toggleParagraphHandler}>Show showParagraph!</Button>
    </div>
  );
}

개발자 도구의 Elements 탭은 DOM에 변화가 있을 때 변화된 부분을 강조해줍니다.

button을 클릭했을 때 새로 생긴 <p>This is new!</p> 이외에 다른 DOM은 강조되지 않습니다.


button을 다시 눌렀을 때 <p>This is new!</p>가 속해있던 div만 강조가 됩니다.





State(상태)

리액트는 컴포넌트와 연결된 상태도 함께 관리합니다.
가장 일반적인 형태의 상태 관리는 useState 후크를 사용하는 것입니다.
useState는 새로운 상태를 만들어서 자동적으로 useState를 호출한 컴포넌트에 연결할 수 있습니다.
그리고 연결된 상태가 변경된 컴포넌트는 다시 렌더링되고 화면에 표시되는 것들이 바뀝니다.

리액트는 useState와 여기에 전달된 기본값에 대해서는 컴포넌트가 처음 렌더링될 때 한 번만 고려되도록 처리합니다.
만약 컴포넌트가 삭제되고 다시 연결되었다면 새로운 상태가 초기화될 수 있습니다.
하지만 DOM에 컴포넌트가 연결되고 유지되는 동안에는 상태는 최초의 초기화 이후에는 갱신만 됩니다.


Schedule

useStatesetState를 사용하여 state를 바꾸려고 할 때 리액트는 바꿀 state를 인지하고 바꿀 계획을 준비하지만 즉시 바꾸지는 않습니다.
리액트는 예정된 상태 변경을 예약하고 연기할 수 있습니다.
상태는 갱신 예악이 된 뒤 컴포넌트가 다시 실행되고 나서야 사용 가능한 최신 상태가 됩니다
또한 변경되어야할 상태가 두 개 이상일 때에 컴포넌트의 재실행, 재평가로 인한 두 번 이상의 변경 작업이 있다고 생각할 수 있지만 변경작업은 단 하나의 프로세스만을 갖습니다.
두 개 이상의 상태를 변경하는 하나의 상태 변경 작업 스케줄이 존재하게 됩다는 말입니다.


문제점

아래는 버튼을 클릭하면 state에 1을 3번 더하는 함수를 실행하는 코드입니다.
1을 3번 더하니 버튼을 클릭하면 console에 3이 출력되는 것을 예상하지만 1이 출력됩니다.

const [state, setState] = useState(0);

const countHandler = () => {
  setState(state + 1);
  setState(state + 1);
  setState(state + 1);
};
console.log(state);
// 1

return <Button onClick={countHandler}>Plus Three</Button>

해결

setState를 콜백 함수처럼 사용하면 동기적으로 사용할 수 있습니다.
문제의 코드 setState(state + 1)에서 state는 재평가 전까지 변하지 않는 state입니다.
따라서 setState(0 + 1)이 3번 반복되는 것이죠.
하지만 함수형으로 사용한 setState()prevState는 재평가 전에도 변화하는 state입니다.

const [state, setState] = useState(0);

const countHandler = () => {
  setState((prevState) => prevState + 1);
  setState((prevState) => prevState + 1);
  setState((prevState) => prevState + 1);
};
console.log(state);
// 3

return <Button onClick={countHandler}>Plus Three</Button>



'변경작업은 단 하나의 프로세스만있다는' 말이 마지막 setState() 하나만 실행한다는 말로 이해가 될 수도 있지만, 그것이 아닙니다.
변경작업 전 모든 setState()가 실행된 후에 더 이상 실행될게 없는 상태를 적용시키는 변경작업이 한 번이라고 생각하면 도움이 될것 같습니다.

0개의 댓글