본문 바로가기
개발공부_Blog/React.js

useMemo, React-hooks(4)

by 소팡팡 2022. 8. 10.

8-4 useMemo

  • 함수 컴포넌트 내부에서 발생하는 연산을 최적화 시키는 Hook이다.
  • 리액트에서 컴포넌트의 렌더링은 state업데이트, 부모컴포넌트 업데이트 등으로 인해 수시로 일어날 수 있다.
    이러한 경우에 불필요한 중복 연산이 발생할 수 있으며 memoization을 활용한 useMemo로 연산을 최적화 시킬 수 있다.
  • Memoizatioin 이란?
    기존에 수행하던 연산의 결과물을 어딘가에 저장해두고 동일한 값이 들어오면 재활용하는 기법이다.

 

랜더링마다 호출되는 컴포넌트 함수

일반적으로 React의 함수형 컴포넌트는 다음과 같은 구조로 작성이 됩니다.

function MyComponent(props) {
  // 어떤 로직 (JavaScript)
  return; /* 어떤 화면 (JSX) */
}

function MyComponent({ x, y }) {
  const z = compute(x, y);
  return <div>{z}</div>;
}

이렇게 작성된 컴포넌트 함수는 React에서 랜더링(rendering)이 일어날 때마다 호출이 된다. 컴포넌트 함수가 호출이 되면 그 안에 자바스크립트 로직들이 수행되고, 이를 기반으로 JSX로 마크업된 UI가 리턴되는 기본 구조를 가지고 있다.

React에서 컴포넌트의 랜더링은 한 번 일어나고 끝이 아니라 수시로 계속 일어날 수 있다.
대표적인 예로 컴포넌트의 자신의 상태 변경(state update)이 일어날 수 있고, 아니면 부모 컴포넌트의 상태 변경이 일어나 랜더링되야 하는 경우도 있다. 사용자가 브라우저에서 새로고침을 할 때도 컴포넌트의 재 랜더링은 불가피 하다.

만약에,
함수가 내부적으로 복잡한 연산을 수행하기 때문에 결과값을 리턴하는 데 오랜 시간이 걸린다면?

컴포넌트가 재랜더링 할 때마다 함수가 호출되므로 사용자가 홈페이지 사용시 불편을 느낄 수 있을 것이다.

 

useMemo 개념

렌더링이 일어날 때마다 compute함수의 인자로 넘어오는 x,y값이 항상 변하는 게 아니라면 compute함수를 계속 호출할 필요가 없다. useMemo를 활용하여 memoization기법을 적용하여 개선할 수 있다. 

 

** momoization 

렌더링이 발생했을 때,  이전 랜더링과 현재 랜더링 간에 x y 값이 동일한 경우, 다시 함수를 호출을 하여 z 값을 구하는 대신, 기존에 메모리의 어딘가에 저장해두었던 z 값을 그대로 사용하는 것입니다.

function MyComponent({ x, y }) {
  const z = useMemo(() => compute(x, y), [x, y]);
  return <div>{z}</div>;

useMemo 함수는 2개의 인자를 받는데
첫번째는 (x , y)는 결과값을 생성해주는 팩토리 함수(=기존에 호출하던 함수)이고, 두번째는 [ x , y ]는 기존 결과값 재활용 여부의 기준이되는 입력값 배열이다. ( 두번째 인자인 배열의 요소 값이 업데이트 될 때만 콜백함수를 호출 )

 

 

 

useMemo적용

import { useState } from "react";

const getAverage = numbers =>{
  console.log('평균값 계산중')
  if (numbers.length === 0) return 0;
  const sum = numbers.reduce((a,b) => a + b)
  return sum / numbers.length;
}

const UseMemoEx = ()=>{

  const [list, setList] = useState([]);
  const [number, setNumber] = useState('');
  
  const handleOnChange = (e)=>{
    setNumber(e.target.value)
  }
  const handleOnClick = (e)=>{
    const nextList = list.concat(parseInt(number))
    setList(nextList)
    setNumber('')
  }

  return (
    <>
      <input value={number} onChange={handleOnChange}/>
      <button onClick={handleOnClick}>등록</button>
      <ul>
        {list.map((value,idx)=>(
          <li key={idx}>{value}</li>
        ))}
      </ul>
      <div>
        <b>평균값 : </b>{getAverage(list)} 
      </div>
    </>
  )
}
export default UseMemoEx;

평균값을 계산할 때만 getAverage함수가 실행되어야 하는데, input에 값을 입력할 때도 getAverage 함수가 실행된다.

그 이유는,
input에 onChange함수가 실행 되면 컴포넌트가 재랜더링 되면서 업데이트가 발생한다. 동시에 getAverage의 인수가 되는 list의 값이 초기화되면서 getAverag함수가 호출된다. 컴포넌트의 재랜더링이 필요할 때마다 함수가 호출되므로 이는 비효율적이다.

useMemo를 사용하여 작업을 최적화 할 수 있다.

useMemo는 렌더링하는 과정에서 특정 값이 바뀌었을 때만 연산을 실행하고, 원하는 값이 바뀌지 않았으면 이전에 연산했던 결과를 다시 사용할 수 있게 해준다.

import { useState, useMemo } from "react";

const getAverage = numbers =>{
  console.log('평균값 계산중')
  if (numbers.length === 0) return 0;
  const sum = numbers.reduce((a,b) => a + b)
  return sum / numbers.length;
}

const UseMemoEx2 = ()=>{

  const [list, setList] = useState([]);
  const [number, setNumber] = useState('');
  
  const handleOnChange = (e)=>{
    setNumber(e.target.value)
  }
  const handleOnClick = (e)=>{
    const nextList = list.concat(parseInt(number))
    setList(nextList)
    setNumber('')
  }

  const avg = useMemo(()=> getAverage(list), [list])

  return (
    <>
      <input value={number} onChange={handleOnChange}/>
      <button onClick={handleOnClick}>등록</button>
      <ul>
        {list.map((value,idx)=>(
          <li key={idx}>{value}</li>
        ))}
      </ul>
      <div>
        <b>평균값 : </b>{avg} 
      </div>
    </>
  )
  
}

export default UseMemoEx2;

변수 avg에 useMemo를 사용하였다.

결과적으로 getAverage함수에 들어가는 list의 내용이 추가될 때만 getAverage함수가 호출된다. 

= input 입력창에 숫자를 입력할 때는 getAverage함수가 작동하지 않는다 

 

 

 

!!!

useMemo는 성능 최적화를 위해 사용할 수는 있지만, 가장 좋은 방법은 아닐 수 있음을 기억하세요!
최대한 useMemo를 사용하지 않고도 동작할 수 있도록 코드를 작성해볼 것(react.공식문서)

 

 

 

참고

https://www.daleseo.com/react-hooks-use-memo/

https://ko.reactjs.org/docs/hooks-reference.html#usememo

'개발공부_Blog > React.js' 카테고리의 다른 글

immer_불변성 유지  (0) 2022.08.21
config.json  (0) 2022.08.15
useReducer, React-hooks(3)  (0) 2022.08.10
useEffect, React-Hooks(2)  (0) 2022.08.10
useState, 가장 기본적인 React-Hooks  (0) 2022.08.10

댓글