Web/React

[React] Reac.memo 함수형 컴포넌트 업데이트 조건 적용방법

usingsystem 2023. 4. 21. 16:20
728x90

Reac.memo는 고차 컴포넌트이다.

 

고차 컴포넌트는 컴포넌트를 가져와 새 컴포넌트를 반환하는 함수입니다.

 

Reac.memo은 똑같은 Prop을 전달받으면 리렌더링 하지 않는다.

 

문자열과 정수형에 memo 사용할 경우

import React, { useEffect, useState } from "react";

const Textview = React.memo(({ text }) => {
  useEffect(() => {
    console.log(`updatae :: text : ${text}`);
  });
  return <div>{text}</div>;
});

const CountView = ({ count }) => {
  useEffect(() => {
    console.log(`updatae :: count : ${count}`);
  });

  return <div>{count}</div>;
};

const OptimizeTest = () => {
  const [count, setCount] = useState(1);
  const [text, setText] = useState("");

  return (
    <div style={{ padding: 50 }}>
      <div>
        <h2>count</h2>
        <CountView count={count} />
        <button
          onClick={() => {
            setCount(count + 1);
          }}
        >
          +
        </button>
      </div>
      <div>
        <h2>text</h2>
        <Textview text={text} />
        <input value={text} onChange={(e) => setText(e.target.value)} />
      </div>
    </div>
  );
};

export default OptimizeTest;

memo를 사용한 Textview에는 count버튼을 눌러도 렌더링 되지 않지만 memo를 사용하지 않은 button에서는 textview를 변경하면 함께 렌더링 되는 걸 확인할 수 있다.

 

객체에 Memo를 사용할 경우

비원시타입에 memo를 사용할 경우 기본적으로 react에서는 얕은 비교(값이 아닌 주소만을 비교하는 방법)를 하게 된다.

그래서 memo를 사용했다고 하더라도 리렌더링된다. 때문에 아래의 areEqual을 사용해 주어야 한다.

 

function MyComponent(props) {
  /* props를 사용하여 렌더링 */
}
function areEqual(prevProps, nextProps) {
  /*
  nextProps가 prevProps와 동일한 값을 가지면 true를 반환하고, 그렇지 않다면 false를 반환
  */
}
export default React.memo(MyComponent, areEqual);

 

areEqual을 사용하지 않은경우

CounterB는 객체를 전달해 준다.

import React, { useEffect, useState } from "react";

const CounterA = React.memo(({ count }) => {
  useEffect(() => {
    console.log(`counterA update ${count}`);
  });

  return <div>{count}</div>;
});
const CounterB = React.memo(({ obj }) => {
  useEffect(() => {
    console.log(`counterB update ${obj}`);
  });

  return <div>{obj.count}</div>;
});

const OptimizeTest = () => {
  const [count, setCount] = useState(1);
  const [obj, setObj] = useState({ count: 1 });

  return (
    <div style={{ padding: 50 }}>
      <div>
        <h2>countA</h2>
        <CounterA count={count} />
        <button
          onClick={() => {
            setCount(count);
          }}
        >
          AButton
        </button>
      </div>
      <div>
        <h2>countB</h2>
        <CounterB obj={obj} />
        <button
          onClick={() => {
            setObj({ count: obj.count });
          }}
        >
          BButton
        </button>
      </div>
    </div>
  );
};

export default OptimizeTest;

areEqual을 사용한 경우

import React, { useEffect, useState } from "react";

const CounterA = React.memo(({ count }) => {
  useEffect(() => {
    console.log(`counterA update ${count}`);
  });

  return <div>{count}</div>;
});
const CounterB = ({ obj }) => {
  useEffect(() => {
    console.log(`counterB update ${obj}`);
  });

  return <div>{obj.count}</div>;
};

const areEqual = (prevProps, nextProps) => {
  return prevProps.obj.count === nextProps.obj.count;
};

const MemoizedCounterB = React.memo(CounterB, areEqual);

const OptimizeTest = () => {
  const [count, setCount] = useState(1);
  const [obj, setObj] = useState({ count: 1 });

  return (
    <div style={{ padding: 50 }}>
      <div>
        <h2>countA</h2>
        <CounterA count={count} />
        <button
          onClick={() => {
            setCount(count);
          }}
        >
          AButton
        </button>
      </div>
      <div>
        <h2>countB</h2>
        <MemoizedCounterB obj={obj} />
        <button
          onClick={() => {
            setObj({ count: obj.count });
          }}
        >
          BButton
        </button>
      </div>
    </div>
  );
};

export default OptimizeTest;
728x90