useMemo 를 사용하면 함수형 컴포넌트 내부에서 발생하는 연산을 최적화할 수 있다. 리액트는 기본적으로 state의 값이 변할 때 마다 새로 렌더링이 이뤄진다. 특정 state 값이 변할 때에만 렌더링을 새로 하면 효율적이겠지만 기본적으로 state의 값 중 하나라도 변하면 렌더링이 새로 이뤄진다는 의미이다. useMemo 는 특정 값이 변했을 경우에만 연산을 실행하고 그렇지 않으면 캐싱되어 있는 결과를 사용하는 방식으로 최적화를 하기 위한 hook이다.
average.jsimport React, { useState } from "react";
const getAverage = num => {
console.log('평균값을 계산중입니다.....')
if (num.length === 0) return 0
const sum = num.reduce((a,b) => a+b)
return sum / num.length
}
const Average = () => {
const [list, setList] = useState([])
const [num, setNum] = useState('')
const onChange = e => {
const { value } = e.target
if (!isNaN(Number(value))) {
setNum(value)
} else {
alert('숫자만 입력 가능합니다.')
}
}
const onInsert = () => {
const nextList = [...list, parseInt(num)]
setList(nextList)
setNum('')
}
return (
<div>
<input value={num} onChange={onChange} type="text"/>
<button onClick={onInsert}>submit</button>
<ul>
{list.map((value, index) => (
<li key={index}>{value}</li>
))}
</ul>
<div>
<b>avg</b>: {getAverage(list)}
</div>
</div>
)
}
export default Average
우선 평균을 구할 숫자들을 담은 list 배열과 숫자 num 을 state로 갖는다.
인풋 태그의 value 가 바뀔 때 마다 숫자가 맞으면 num 을 갱신해준다.
submit 버튼 클릭 시 list 배열에 갱신된 num 을 넣어준다.
{getAverage(list)} 로 평균을 보여준다.
하지만 이러한 방식은 두 번째 과정에서 num을 갱신해줄 때 마다 getAverage 함수를 재실행하기 때문에 최적의 방법이라 말하기 어렵다. 이를 해결하기 위해 list 가 바뀌기 전 까지는 기존 값을 가지고 있다가 바뀐 후에 새로 계산하는 방식을 useMemo 로 구현할 수 있다.
useMemo로 최적화하기import React, { useState, useMemo } from "react";
const Average = () => {
...
...
const avg = useMemo(() => getAverage(list), [list])
return (
...
...
<b>avg</b>: { avg }
)
}
첫번째 인자에 콜백함수를, 두번째 인자에 변하기를 원하는 state 값을 설정해 주면 해당 값이 변할 때에만 함수를 재실행해 렌더링을 효율적으로 조정할 수 있다. 이를 통해 list 배열이 바뀔 때에만 getAverage 함수를 호출할 수 있다.