DBILITY

react memo, useMemo, useCallback 본문

front-end & ui/react

react memo, useMemo, useCallback

DBILITY 2023. 6. 16. 11:33
반응형

react는 state(data)가 변경될때마다 그에 따라 Component를 다시 렌더링한다. 다시 그린다고 생각하자.

확인하고 싶으면 크롬 확장프로그램 React Developer Tools를 설치하고 다음과 같이 설정해 보면 확인 가능하다.

다음과 같이 테스트용 App을 작성했다.

App에 button click event와 Child Component가 있다.

import React, {JSX, useEffect, useState} from 'react';
import './App.css';

function App(): JSX.Element {
  const [date, setDate] = useState<Date>(new Date());
  return (
    <div className="App">
      <TestComponent></TestComponent>
      <button onClick={() => setDate(new Date())}>Click</button>
    </div>
  );
}

const TestComponent = (): JSX.Element => {

  console.log('rendering');

  useEffect(() => {
    console.log('mount');
  }, []);

  return (
    <div style={{margin: 10}}>
      TestComponent
    </div>
  );
}

export default App;

React Developer Tools에서 Highlight updates when components render를 활성화하고 click event를 발생해보면 다음과 같이 확인 할 수 있다.

Component의 불필요한 re-rendering을 방지하고 싶은 경우 memo fucntion을 사용할 수 있다. 말이 좀 그렇다.

이때 해당 Component는 함수 선언식이 아닌 함수 표현식으로 작성되어야 한다.

const TestComponent = memo((): JSX.Element => {

  console.log('rendering');

  useEffect(() => {
    console.log('mount');
  }, []);

  return (
    <div style={{margin: 10}}>
      TestComponent
    </div>
  );
})

다음과 같이 동작하는 것을 볼 수 있다.

물론 props가 전달이 되고 props에 변경이 일어나는 경우는 당연히 re-rendering이 된다.

date를 props로 전송해 보자.

import React, {JSX, memo, useEffect, useState} from 'react';
import './App.css';

function App(): JSX.Element {
  const [date, setDate] = useState<Date>(new Date());
  return (
    <div className="App">
      <TestComponent date={date}></TestComponent>
      <button onClick={() => setDate(new Date())}>Click</button>
    </div>
  );
}

const TestComponent = memo((props: { date: Date }): JSX.Element => {
  const {date} = props;
  console.log('rendering');

  useEffect(() => {
    console.log('mount');
  }, []);

  return (
    <div style={{margin: 10}}>
      TestComponent
    </div>
  );
})

export default App;

 

click할때마다 date가 변하기 때문에 re-rendering된다. 상식적인 작동방식이다.

memo function은 정의는 다음과 같다. Component의 preProps와 nextProps를 비교해서 동작하게 되어 있다.

useMemo hook은 useEffect mount시 동작과 비슷하다. 함수의 동작과 그 결과 값에 대해

re-rendering이 일어나더라고 memorization된 값을 반환한다. 필요할 때 사용하자. deps가 변할때만 실행 할 수 도 있다.

연산 cost가 높을 것으로 예상되는 경우에 사용하면 되겠다. 세상만사 과유불급이다.

다음은 rendering 시 날짜를 반환하는 함수를 한번만 실행하게 된다.

import React, {JSX, memo, useEffect, useMemo, useState} from 'react';
import './App.css';
import moment from "moment";

function App(): JSX.Element {
  const [date, setDate] = useState<Date>(new Date());
  return (
    <div className="App">
      <TestComponent date={date}></TestComponent>
      <button onClick={() => setDate(new Date())}>Click</button>
    </div>
  );
}

const TestComponent = (props: { date: Date }): JSX.Element => {
  const {date} = props;
  console.log('rendering');

  const result = useMemo(() => {
    return moment(new Date()).format("YYYY-MM-DD HH:mm:ss.SSS");
  }, []);
  console.log(result);

  useEffect(() => {
    console.log('mount');
  }, []);

  return (
    <div style={{margin: 10}}>
      TestComponent {result}
    </div>
  );
}

export default App;

useMemo가 계산된 결과 값의 재사용이라면 useCallback은 callback 함수의 재사용이다.

react 함수형 콤포넌트는 함수라는 것을 기억하자. javascript에서 함수는 객체다. 이것을 기억하면 이해가 수월하다.

callback으로 넘어온 함수를 기억하고 deps에 변경이 일어나면 넘겨준 함수를 그렇지 않으면 기억하고 있는 함수를 러턴한다.

setState나 dispatch처럼 이미 최적화된 함수에는 사용하지 않는게 좋다고 한다. Child Component에 props로 전달되는 함수의 경우 불변성이 중요하다면 해주는게 좋다고 한다. 뭔 말이지? 결국 참조에 의한 호출(call by reference)에 대한 얘기인가?

반응형

'front-end & ui > react' 카테고리의 다른 글

react .env  (0) 2023.06.09
react image src path  (0) 2023.06.09
react react-toastify  (0) 2023.06.09
react redux redux-toolkit  (0) 2023.04.13
react styled component  (0) 2023.04.12
Comments