【React】useCallback과 useMemo에 의한 표시 퍼포먼스 개선

이전에는 React.memo에 의한 React 디스플레이 성능 개선에 대해 요약했습니다.
이에 이어 이번에는 React.memo와 함께 사용되는 Hooks인 useCallbackuseMemo에 대해 조사하여 렌더링 거동을 검증했습니다.

useCallback


useCallback는 메모된 콜백 함수를 반환하는 React Hooks입니다.
인라인의 콜백 함수와 그것이 의존하는 값의 배열을 건네주면useCallback 는 그 콜백 함수를 메모화한 것을 돌려주고 그 함수는 의존 배열의 요소의 어느 쪽인가가 변화했을 경우에 만 변경됩니다.
useCallback는 주로 부모 구성 요소에서 사용되며 메모 된 콜백 함수는 하위 구성 요소의 props로 전달됩니다.
자식 구성 요소를 React.memo로 내보내는 경우 props 변경이 없으면 추가 렌더링이 발생하지 않습니다.
이 방법으로 React의 표시 성능을 향상시킬 수 있습니다.

검증



Log name을 누르면 console.log에 문장이 출력되고 Increase Count1(2)를 누르면 카운트가 표시되는 화면을 만들었습니다.
렌더링시에 functionslogName 함수가 추가되도록 하고 useCallback 의 사용 유무로 그 거동이 어떻게 바뀌는지를 조사했습니다.


useCallback을 사용하지 않는 경우



화면의 구현은 다음과 같습니다.

App.js
import React from 'react';
import logo from './logo.svg';
import './App.css';

const functions = new Set();

const App = () => {
  const [count1, setCount1] = useState(0);
  const [count2, setCount2] = useState(0);

  const incrementCount1 = () => setCount1(count1 + 1);
  const incrementCount2 = () => setCount2(count2 + 1);

  const logName = () => console.log('Yihua');

  functions.add(logName); //レンダリングの度にfunctionsインスタンスにlogName関数が追加される

  console.log(functions);

  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        Count1: {count1}
        <button onClick={incrementCount1}>Increase Count1</button>
        Count2: {count2}
        <button onClick={incrementCount2}>Increase Count2</button>
        <button onClick={logName}>Log name</button>
      </header>
    </div>
  );
};

export default App;

Increase Count1(혹은 2)을 누르면 State(count1, count2)의 변화가 일어나기 때문에, 카운트가 증가할 때마다 재렌더링됩니다.
결과적으로 렌더링할 때마다 functionslogName 함수가 추가되었습니다.


useCallback을 사용하는 경우


const logName = () => console.log('Yihua');로 표시된 부분을 useCallback로 다시 씁니다.
이 때, 제2 인수에는 빈 배열을 주고 있으므로, 초기 표시로 메모화를 실시한 후에 함수의 재생성은 일어나지 않습니다.

App.js
  const logName = useCallback(() => console.log('Yihua'), []);

결과적으로 Increase Count1(2)을 여러 번 눌러도 functions에는 logName 함수가 추가되지 않습니다 (Set(1)이 아닌 이유는 조사 중)


useMemo


useCallback에서는 콜백 함수를 메모했지만 useMemo는 값을 메모합니다.

“만들기” 함수와 그것이 의존하는 값의 배열을 전달하고 종속 배열의 요소 중 하나가 변경된 경우에만 메모된 값을 다시 계산합니다.
이 최적화를 사용하면 렌더링 당 비용이 많이 드는 계산을 피할 수 있습니다.
useMemouseCallback와 마찬가지로 React.memo와 함께 사용됩니다.

검증



Increase Count1을 누를 때만 doSomethingComplicated 함수가 실행되고 계산 결과가 complexValue로 표시되는 화면을 구현했습니다.


useMemo를 사용하지 않는 경우


doSomething 함수를 추가하여 complexValue: {doSomethingComplicated()}로 표시합니다.

App.js
  //レンダリングの度に実行される
  const doSomethingComplicated = () => {
    console.log('I am computing something complex');
    return ((count1 * 1000) % 12.4) * 51000 - 4000;
  };

  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        Count1: {count1}
        <button onClick={incrementCount1}>Increase Count1</button>
        Count2: {count2}
        <button onClick={incrementCount2}>Increase Count2</button>
        complexValue: {doSomethingComplicated()}
        <button onClick={logName}>Log name</button>
      </header>
    </div>
  );

그러면 렌더링 할 때마다 (Increase Count1뿐만 아니라 Increase Count2를 눌러도) doSomethingComplicated의 console.log가 실행됩니다.


useMemo를 사용하는 경우


doSomethingComplicateduseMemo로 다시 작성하면 다음과 같습니다.
두 번째 인수에 제공된 count1의 값이 변경될 때만 새 값을 반환합니다.
  const doSomethingComplicated = useMemo(() => {
    console.log('I am computing something complex');
    return ((count1 * 1000) % 12.4) * 51000 - 4000;
  }, [count1]);

또한 doSomethingCompleted는 값을 반환하므로 다음을 다시 작성합니다.
complexValue: {doSomethingComplicated}

이렇게하면 Increase Count2를 아무리 눌러도 doSomethingCompleted가 실행되지 않습니다.

참고 자료

좋은 웹페이지 즐겨찾기