[React] useMemo와 useCallback Hook을 알아보자!!
useMemo Hook과 useCallback Hook은 메모이제이션( memoization )을 활용하는 React Hook입니다.
memoization이란?
어떠한 연산의 수행한 결과값을 메모리 내에 저장하여 동일한 입력이 들어오는 경우 기존에 메모리에 저장된 연산 결과를 그대로 반환해주는 프로그래밍 기법입니다.
memoization은 중복된 연산을 피하기 때문에 메모리를 조금 더 사용하더라도 애플리케이션의 성능을 최적화 할 수 있습니다.
이러한 특성을 이용해 React의 Component가 동일한 입력에 대해 재렌더링 되는 상황을 막을 수 있는 유용한 Hook입니다.
useMemo란??
useMemo 함수는 메모이제이션된 값을 반환하는 Hook입니다.
하위 컴포넌트에서 2개의 props 인자를 받는 컴포넌트가 존재할 때
메모이제이션되지 않은 컴포넌트인 경우 2개 인수 중 1개의 인수만 state가 변경되어 부모로부터 전달받을때
2개의 인자 모두 재랜더링이 진행됩니다.
이를 useMemo 함수를 이용한다면 2개 인자 중에 1개만 state가 변경되어도 변경된 인자에게만 영향받는 값만 재랜더링됩니다.
React 공식 홈페이지의 useMemo 문법
useMemo가 적용되지 않은 예시입니다.
부모 컴포넌트
import react, { useState, useMemo, useCallback } from "react";
import "./styles.css";
export default function App() {
console.log("부모!");
const [name, setName] = useState("");
const [age, setAge] = useState("");
//기존 유저 이름 변경 함수
const onChangeName = (e) => {
const data = e.target.value;
console.log("data : ", data);
setName(data);
};
//기존 유저 이름 변경 함수
const onChangeAge = (e) => {
const age = e.target.value;
console.log("age : ", age);
setAge(age);
};
return (
<div className="App">
<h1>부모 컴포넌트</h1>
<User
name={name}
age={age}
onChangeName={onChangeName}
onChangeAge={onChangeAge}
/>
</div>
);
}
하위 컴포넌트
import react from "react";
const setNameTag = (name) => {
console.log("이름 태그");
return `이름은 : ${name}`;
};
const setAgeTag = (name) => {
console.log("나이 태그");
return `나이는 : ${name}`;
};
const User = (props) => {
console.log("자식");
//일반적인 props 받은 값
const naem = setNameTag(props.name);
const age = setAgeTag(props.age);
return (
<div>
<h1>{naem}</h1>
<h1>{age}</h1>
<div>
<input type="text" onChange={(e) => props.onChangeName(e)} />
</div>
<div>
<input type="text" onChange={(e) => props.onChangeAge(e)} />
</div>
</div>
);
};
useMemo를 적용하지 않은 결과
useMemo를 적용한 자식 컴포넌트
import react, { useMemo } from "react";
const User = (props) => {
console.log("자식");
// //일반적인 방식
// const naem = setNameTag(props.name);
// const age = setAgeTag(props.age);
//useMemo 적용
const naem = useMemo(() => setNameTag(props.name), [props.name]);
const age = useMemo(() => setAgeTag(props.age), [props.age]);
return (
<div>
<h1>{naem}</h1>
<h1>{age}</h1>
<div>
<input type="text" onChange={(e) => props.onChangeName(e)} />
</div>
<div>
<input type="text" onChange={(e) => props.onChangeAge(e)} />
</div>
</div>
);
};
useMemo를 적용한 결과
onChange로 props에 입력 받은 값만 재랜더링 되는 결과를 볼 수 있습니다.
useCallback이란??
useCallback 함수는 메모이제이션된 콜백 함수를 반환하는 Hook입니다.
React 공식 홈페이지의 useCallback hook 문법
반환하는 콜백함수의 반환값이 0인 경우와 1인 경우가 있다고 가정했을 때
0을 반환하는 함수와 1을 반환하는 함수는 서로 다른 참조값( 주소값 )을 갖습니다.
이를 통해 메모리에 메모이제이션함으로써 반환값이 같은 경우 연산하지 않고 해당 함수의 주소값을 참조해 반환합니다.
onChangeAge 함수에만 useCallback Hook을 감싼 예제입니다.
import react, { useState, useMemo, useCallback } from "react";
import "./styles.css";
export default function App() {
console.log("부모!");
const [name, setName] = useState("");
const [age, setAge] = useState("");
let count = 0;
//기존 유저 이름 변경 함수
const onChangeName = (e) => {
console.log("onChangeName count 값 : ", count);
count++;
const data = e.target.value;
console.log("data : ", data);
setName(data);
};
//useCallback 사용
const onChangeAge = useCallback((e) => {
console.log("onChangeAge count 값 : ", count);
count++;
const age = e.target.value;
console.log("age : ", age);
setAge(age);
}, []);
return (
<div className="App">
<h1>부모 컴포넌트</h1>
<User
name={name}
age={age}
onChangeName={onChangeName}
onChangeAge={onChangeAge}
/>
</div>
);
}
onChangeAge만 useCallback을 사용한 결과
onChangeAge의 함수만 변경되는 결과를 확인할 수 있습니다.
useMemo와 useCallback은 React 성능 최적화에 필수인 hook인 만큼 사용하기에는 많은 코드 경험을 요구하는 것 같습니다.
이번 포스팅으로 React 공부에 도움이 되었으면 좋겠네요.