JiSoo's Devlog

[Udemy React 완벽 가이드] Section 11 본문

Frontend/React

[Udemy React 완벽 가이드] Section 11

지숭숭숭 2024. 1. 4. 11:46

리액트가 실제로 작동하는 방식

  • 리액트는 사용자 인터페이스 구축을 위한 자바스크립트 라이브러리
  • 리액트는 컴포넌트를 통해 사용자 인터페이스를 효과적으로 구성하며 이에 대한 업데이트 역시 컴포넌트를 통해 한다
  • 리액트 DOM은 웹에 대한 인터페이스
  • 리액트는 변경된 내용과 어떤 화면이든 간에 화면에 표시되어야 할 정보 모두를 현재 사용 중인 인터페이스에 전달한다
  • 리액트 DOM은 브라우저의 일부인 실제 DOM에 대한 작업을 하므로 사용자가 보고 있는 화면에 무언가를 표시하는 역할은 리액트 DOM의 몫이다
  • 상태가 업데이트되면 이 정보를 리액트 DOM으로 전달되어 갱신 전후의 상태 차이를 인식하고 리액트가 컴포넌트 트리를 통해 구성한 가상 스냅샷인 가상 DOM과 일치하도록 실제 DOM을 조작하는 방법을 알 수 있게 한다
  • 리액트에 의해 컴포넌트 함수가 재실행된다고 해서 실제 DOM의 각 부분들이 다시 렌더링 된다던가 재평가되는 것은 아니다
  • 컴포넌트는 상태, props, 컨텍스트가 변경될 때 재평가된다
  • 실제 DOM은 리액트가 구성한 컴포넌트의 이전 상태와 트리, 그리고 현재의 상태 간의 차이점을 기반으로 변경이 필요할 때만 업데이트된다
  • 리액트는 가상 DOM 과의 비교를 통해 최종 스냅샷과 현재 스냅샷을 실제 DOM에 전달하는 구조를 갖는다

 

 

컴포넌트 업데이트 실행 중

import React, { useState } from 'react';

import Button from './components/UI/Button/Button';
import './App.css';

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

  console.log('APP RUNNING');

  const toggleParagraphHandler = () => {
    setShowParagraph((prevShowParagraph) => !prevShowParagraph);
  };

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

export default App;
 
 
 

 

 

 

자식 컴포넌트 재평가 자세히 살펴보기

  • 다른 컴포넌트의 단락에 시각적으로 영향을 준다고 해서 App 컴포넌트가 재평가되지 않거나 그런 것은 아니다
  • 자식 컴포넌트는 부모 컴포넌트의 일부분이니까 부모 컴포넌트 함수가 재실행되면 마찬가지로 자식 컴포넌트 함수도 재실행되기 때문에 props 값은 상관이 없다
  • props의 변경은 실제 DOM의 변경으로 이어질 수는 있지만 함수에서 재평가를 할 때는 부모 컴포넌트가 재평가되는 것으로 충분하다
  • 컴포넌트 재평가와 컴포넌트 함수의 재실행이 일어나도 실제 DOM이 다시 렌더링 되거나 변경되는 것은 아니다
  • 컴포넌트가 재실행되면 이의 모든 자식 컴포넌트들 역시 재실행, 재평가된다

 

 

react.memo()로 불필요한 재평가 방지하기

  • React.memo는 함수형 컴포넌트를 최적화할 수 있다
  • React.memo는 인자로 들어간 컴포넌트에 어떤 props가 입력되는지 확인하고 입력되는 모든 props의 신규 값을 확인한 뒤 이를 기존의 props의 값과 비교하도록 리액트에게 전달한다
  • props의 값이 바뀐 경우에만 컴포넌트를 재실행 및 재평가하게 된다
  • 컴포넌트의 props 값이 바뀌지 않았다면 컴포넌트 실행은 건너뛴다
  • 모든 컴포넌트에 적용하지 않는 이유는 최적화에는 비용이 따르기 때문
  • 리액트가 기존의 props 값을 저장할 공간이 필요하고 비교하는 작업도 필요한데 이 각각의 작업은 개별적인 성능 비용이 필요하다
  • 부모 컴포넌트를 매번 재평가할 때마다 컴포넌트의 변화가 있거나 props의 값이 변화할 수 있는 경우라면 컴포넌트의 재렌더링이 필요하기 때문에 React.memo는 크게 의미를 갖지 못한다
  • 컴포넌트 트리에서 잘라낼 수 있는 몇 가지의 주요 컴포넌트 부분을 선택해 React.memo를 사용하면 된다

 

 

useCallback()으로 함수 재생성 방지하기

  • React.memo는 객체 외에 prop 값에도 작동하게 할 수 있다
  • useCallback 훅을 통해 할 수 있는데 이 훅은 기본적으로 컴포넌트 실행 전반에 걸쳐 함수를 저장할 수 있게 하는 훅으로 리액트에 이 함수를 저장할 것이고 매번 실행 때마다 이 함수를 재생성할 필요가 없다는 것을 알릴 수 있다
  • 동일한 함수 객체가 메모리의 동일한 위치에 저장되므로 이를 통해 비교 작업을 할 수 있다
  • useCallback의 두 번째 인자는 호출에 대한 의존성 배열이어야 한다

 

 

useCallback() 및 해당 종속성

  • useCallback을 사용하면 함수를 저장하고 이를 재사용할 수 있다
import React, { useState, useCallback } from "react";

import Button from "./components/UI/Button/Button";
import "./App.css";
import DemoOutput from "./components/Demo/DemoOutput";

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

  console.log("APP RUNNING");

  const toggleParagraphHandler = useCallback(() => {
    if(allowToggle){
      setShowParagraph((prevShowParagraph) => !prevShowParagraph);

    }
  }, [allowToggle]);

const allowToggleHandler =()=>{
  setAllowToggle(true)
}

  return (
    <div className="app">
      <h1>Hi there!</h1>
      <DemoOutput show={showParagraph} />
      <Button onClick={allowToggleHandler}>Allow Toggling</Button>
      <Button onClick={toggleParagraphHandler}>Toggle Paragraph!</Button>

    </div>
  );
}

export default App;
 
 

 

 

State 스케줄링 및 일괄 처리 이해하기

  • 대부분의 경우에는 상태 변경이 발생하면 상태 갱신에 대한 스케줄 작업은 매우 빠르게 발생한다
  • 실제로는 순간적으로 발생
  • 버튼을 클릭하고 단락을 제거하게 되면 인간은 거의 즉시 작업이 처리된 것으로 보이지만 리액트는 이 상태 변화를 지연시킨다
  • 대다수의 성능 기반의 작업들이 거의 동시에 진행되는데 잠재적으로 리액트는 더 높은 우선순위를 갖는 것으로 간주한다
  • 스케줄링 때문에 다수의 예약 상태 변화가 동시에 있을 수 있는데 이로 인해 여러 번의 갱신이 스케줄 될 수 있으므로 상태를 갱신할 때는 함수 형태를 이용해 갱신하는 것을 추천

 

 

useMemo()로 최적화하기

  • 정렬은 컴포넌트에서 수행 가능한 대표적인 성능 집약적 작업 중 하나
  • useMemo는 모든 종류의 데이터를 저장할 수 있다
  • useMemo는 2개의 인자 필요, 의존성 배열을 통해 저장된 값에 변경 사항이 생길 때마다 업데이트된다
  • useMemo를 사용해 데이터를 저장하면 이는 메모리를 사용하는 것이고 이런 함수 저장 또한 일정 성능을 사용하는 것이다

 

728x90