본문 바로가기
Front-End/React.js

React.memo 실험

by kk님 2023. 3. 17.

이전에도 React.memo 개념글을 작성한 적이 있는데, https://hello-kk.tistory.com/679

리-렌더링을 막기 위한 방법으로 다시 접근해보니 새로워서 다시 정리했다.

//App.jsx

import { Fragment, useState } from "react";
import Tmp from "./Components/Tmp";

function App() {
  const [state, setState] = useState(1);
  const handleButton = () => {
    setState((prev) => prev + 1);
  };
  return (
    <Fragment>
      <div>hi~</div>
      <div>{state}</div>
      <button onClick={handleButton}>버튼</button>
      <Tmp />
    </Fragment>
  );
}
export default App;

(1) React.memo를 사용하지 않은경우

버튼을 매번 클릭할때마다 console.log()에 'Tmp 컴포넌트'가 클릭 수만큼 출력되어 나온다. => 클릭 수만큼 리-렌더링

//Tmp.jsx
function Tmp() {
  console.log("Tmp 컴포넌트");
  return <div>hello~</div>;
}
export default Tmp;

(2) React.memo를 사용한 경우

버튼을 매번 클릭하더라도 <Tmp>의 props가 변하지 않았다면 리-렌더링 되지 않는다.

//Tmp.jsx
import React from "react";

function Tmp() {
  console.log("Tmp 컴포넌트");
  return <div>hello~</div>;
}
export default React.memo(Tmp);

(3) React.memo를 사용했을 때 버튼1과 버튼2로 리-렌더링 관찰하기

  - 버튼1의 기능 : App 컴포넌트에서만 사용되는 'state'(변수명) 값만을 변화하여 App컴포넌트를 리-렌더링

  - 버튼2의 기능 : App컴포넌트에서 선언한 'cnt'를 Tmp 컴포넌트에 전달하여 리-렌더링

//App.jsx

import { Fragment, useState } from "react";
import Tmp from "./Components/Tmp";

function App() {
  const [state, setState] = useState(1);
  const [cnt, setCnt] = useState(1);
  const handleButton1 = () => {
    setState((prev) => prev + 1);
    console.log(cnt, "app");
  };
  const handleButton2 = () => {
    console.log(cnt, "app");
    setCnt((prev) => prev + 1);
  };
  return (
    <Fragment>
      <div>hi~</div>
      <div>{state}</div>
      <button onClick={handleButton1}>버튼1</button>
      <button onClick={handleButton2}>버튼2</button>
      <Tmp cnt={cnt} />
    </Fragment>
  );
}
export default App;

.

//Tmp.jsx

import React from "react";

function Tmp(props) {
  const { cnt } = props;
  console.log("Tmp 컴포넌트", cnt);
  return (
    <div>
      <div>hello~</div>
      <div>{cnt}</div>
    </div>
  );
}
export default React.memo(Tmp);

최초 실행 상태
버튼1을 여러번 클릭한 경우.
버튼 2를 여러번 클릭한 경우

자식 컴포넌트에서 props가 변하지 않는 경우 리-렌더링을 막는 방법 : React.Memo.

아무래도 props가 없는 컴포넌트에 주로 쓰일 것 같다. 혹은 상위 컴포넌트에서 빈번하게 랜더링이 발생하는 경우에도.. 그렇지만 props 를 비교하는 과정이 있다고 하니, trade-off를 생각해보아야 할 것 같다.

 

contextAPI에서는 어떻게 될까 똑같을까?

흠. 신기하게도

ContextAPI 프로바이더 안의 React.memo가 동작하는 방식은 2가지 정도 되는 것 같다. 다른 경우의 수가 있는지는 모르겠지만, 실행해본 결과

(1) 컴포넌트가 useContext()를 이용해서 props를 받는 경우,  React.memo로 감싸고 props가 변경되지 않더라도

 => 리-렌더링 된다. 

(2) 컴포넌트가 useContext()를 이용해서 props를 받지 않는 경우, React.memo로 감싸면

 => 리-렌더링 되지 않는다.

 

그런데, 특이하게도

<Provider >

    <컴포넌트 1>    // React.memo를 사용O, useContext 사용 X => 리-렌더링 X

        <컴포넌트 2 />    // React.memo를 사용O, useContext 사용O => 리-렌더링 O

    <컴포넌트 1>

<Provider />

 

컴포넌트 1은 React.memo를 사용하되 useContext를 사용하지 않고,

컴포넌트 2는 React.memo를 사용하면서 useContext를 사용한 경우에

=> 컴포넌트 1은 리-렌더링 되지 않지만, 컴포넌트 2는 리-렌더링 된다.

 

Provider 컴포넌트가 리-렌더링 되면 useContext()를 받는  컴포넌트는 무조건 리-렌더링 된다. value 가 바뀌지 않더라도.

그런데, useContext를 사용하지 않는 하위 컴포넌트 중 React.memo를 사용했다면 하위 컴포넌트는 리-렌더링 되지 않는다.

 

React.memo는 어떤 때 써야 하는 걸까? 하는 고민이 생겼는데..

script 문제? paint 문제?

컴포넌트가 하는 일이 많은 경우. 부하가 큰 경우..?

'Front-End > React.js' 카테고리의 다른 글

Virtual DOM  (0) 2023.03.23
state 란? 무엇인가 . . .🙄  (0) 2023.03.22
state 관리 대상 줄이기를 고민하다가 => useMemo, useCallback까지  (0) 2023.03.17
useState의 setState((prev)=> !prev)  (0) 2023.03.14
커스텀 훅  (0) 2023.03.14