useMemo

HSKwon·2023년 5월 12일
0
post-thumbnail

useMemo

useMemo는 이전 값을 기억해서 성능을 최적화하는 용도로 사용된다. useMemo에서 memomemoization을 의미한다. 프로그램이 동일한 연산을 반복해야 할 때, useMemo hook에 의존하고 있는 배열인 의존성배열에 입력한 값이 변하지 않는다면 기존에 연산해두었던 값을 재사용하는 방식으로 성능을 최적화 한다.

useMemo의 구조

const value = useMemo(() => {
	return myFunction()
},[values])

useMemo는 두가지의 파라미터를 받는다. 첫번째는 콜백함수이고, 두번째는 의존성배열이다.
첫번째 인자인 콜백함수의 반환값이 useMemo의 반환값이 되고, 두번째 인자인 의존성배열 내부의 값이 업데이트 될 때만 콜백함수를 재실행하여 메모이제이션해두었던 값을 업데이트한다.
useEffect의 의존성배열과 마찬가지로, useMemo 역시 의존성배열이 빈배열일때는 최초 렌더링될 때 한번만, 생략할 경우 모든 렌더링마다 실행, 배열에 값이 있을때에는 값이 업데이트 될 때만 실행된다.

문제상황

Q : 왜 easy calculate의 input에만 1씩 증가시켰는데 결과값이 리턴되는데 1초 이상이 걸릴까...?

import './App.css'
import {useState, useRef, useEffect, useMemo} from 'react'

export default function App() {
  const [hardNumber, setHardNumber] = useState(1);
  const [easyNumber, setEasyNumber] = useState(1);
 
   const hardCalculate = number => {
   console.log('어려운계산');
   for (let i =0; i<1000000; i++) {} // 생각하는 시간
   return number + 1000;
 }


  const easyCalculate = number => {
    console.log('쉬운계산');
    return number + 1;
  }

  const hardSum = hardCalculate(hardNumber);
  const easySum = easyCalculate(easyNumber);

  return (
    <div>
      <h1>hard calculate</h1>
      <input type="number" onChange={e => setHardNumber(parseInt(e.target.value))}/>
      <span> + 1000 = {hardSum}</span>
      <br/>
      <br/>
        <h1>easy calculate</h1>
      <input
        type="number"
        value={easyNumber}
        onChange={e => setEasyNumber(parseInt(e.target.value))}
      />
      <span> + 1 = {easySum} </span>
    </div>
  )
}

A : App 컴포넌트는 함수형 컴포넌트이다. 즉, input에 값을 입력하면 easyNubmer와 관련된 useState의 세터가 변경되고 -> App 컴포넌트가 리렌더링되고 -> easySum 변수와 hardSum 변수가 모두 초기화 되는것!!

hardCalculate 함수는 for 문을 1000000번 실행하고 난 뒤, return 하는 함수이다. 또한, easy calculate의 input 값을 입력하기만 해도 useState의 세터 함수가 변경되어, 컴포넌트가 리렌더링되어 hardNumber 또한 리렌더링 되고, hardCalculate 함수의 무거운 연산을 다시 하게 된다.


콘솔로 확인해보면, easy calculate 의 input에만 값을 입력했는데도 hard calculate함수가 계속해서 재 실행되는 모습이다.

easyNumber state를 변경했을때 hardSum 함수가 호출되지 않게 할 수 없을까?

useMemo로 리팩토링 하기

import './App.css'
import {useState, useRef, useEffect, useMemo} from 'react'

export default function App() {
  const [hardNumber, setHardNumber] = useState(1);
  const [easyNumber, setEasyNumber] = useState(1);

   
   const hardCalculate = number => {
   console.log('어려운계산');
   for (let i =0; i<1000000; i++) {} // 생각하는 시간
   return number + 1000;
 }

   
  
  const easyCalculate = number => {
    console.log('쉬운계산');
    return number + 1;
  }

   // 1️⃣ hardNumber의 값이 변경될 경우에만 hardSum 변수를 초기화한다
   // easyNumber의 값을 변경하더라도, hardSum은 useMemo를 통해 메모이제이션한 값을
   // 사용할 것이며, hardNumber가 변경될 경우에만 기존의 메모이제이션을
   // 새로 계산한 값으로 대체한다.
   const hardSum = useMemo(() => {
     return hardCalculate(hardNumber)
   },[hardNumber]); // 의존성 배열 값이 변경되어야만 return문의 내용이 초기화된다.
  
   // 2️⃣ 마찬가지로 easySum 역시 콜백함수의 결과값을 메모이제이션 해 놓는다.
   const easySum = useMemo(() => {
     return easyCalculate(easyNumber)
   },[easyNumber])

  return (
    <div>
      <h1>hard calculate</h1>
      <input type="number" onChange={e => setHardNumber(parseInt(e.target.value))}/>
      <span> + 1000 = {hardSum}</span>
      <br/>
      <br/>
        <h1>easy calculate</h1>
      <input
        type="number"
        value={easyNumber}
        onChange={e => setEasyNumber(parseInt(e.target.value))}
      />
      <span> + 1 = {easySum} </span>
    </div>
  )
}

useMemo에서 주어진 조건이 만족되지 않았다면, 컴포넌트가 리렌더되더라도 메모이제이션한 값이 초기화되지 않고 유지된다. 주어진 조건의 만족이란 의존성 배열의 값이 변경되었을 경우를 말한다.

profile
공부한 내용이나 관심 있는 정보를 글로 정리하며 익숙하게 만들고자 합니다.

0개의 댓글