useState, useEffect, useRef만 알지말고 useMemo, useCallback도 알아보자.
const memoizedValue = useMemo(() => expensiveWork(num), [num])
이런식으로 useMemo는 두번째 인자에오는 의존성 배열안의 값 num
이 변할때만 expensiveWork, 즉 어떠한 계산을 다시하고, num
이 변하지 않으면 어떠한 계산에 대한 결과를 기억했다가 (어떠한 값이다) 재사용하는 Hook 메소드이다.const memoizedCallback = useCallback(func, [deps])
로 사용하며 useMemo와 같이 두번째인자인 deps가 변경되지 않으면 함수를 기억하고 deps가 변경되면 다시 새로운 reference를 받는다.
이 useCallback도 불필요하게 다시 함수가 재정의되는걸 막아 최적화를 도와준다.
useCallback은 특히 자식컴포넌트가 pureComponent로
shoudComponentUpdate
가 구현되어 있을 때 사용이 유용하다.
바로 예시를 봐보자.
//App.js
import React, { useState, useMemo, useCallback } from "react";
import Child from "./components/Child";
const translateCountry = (country) => {
console.log("나라번역중..");
switch (country) {
case "korea":
return "한국";
case "japan":
return "일본";
case "usa":
return "미국";
case "china":
return "중국";
default:
return "어딘지 잘모르겠어요..";
}
};
const translateCity = (city) => {
console.log("도시 번역중..");
switch (city) {
case "seoul":
return "서울";
case "tokyo":
return "도쿄";
case "washington":
return "워싱턴";
case "beijing":
return "북경";
default:
return "어딘지 잘모르겠어요..";
}
};
const App = () => {
const [country, setCountry] = useState("");
const [city, setCity] = useState("");
// useMemo 사용 x
const myCountry = translateCountry(country);
const myCity = translateCity(city);
// useMemo 사용 0
// const myCountry = useMemo(() => translateCountry(country), [country]);
// const myCity = useMemo(() => translateCity(city), [city]);
// useCallback 사용 x
const onChangeHandler = (e) => {
if (e.target.id === "country") setCountry(e.target.value);
else setCity(e.target.value);
};
// useCallback 사용 0
// const onChangeHandler = useCallback((e) => {
// if (e.target.id === "country") setCountry(e.target.value);
// else setCity(e.target.value);
// }, []);
return (
<>
<div>
<label>
What is your country ?
<input id="country" value={country} onChange={onChangeHandler} />
</label>
</div>
<label>
What is your city ?
<input value={city} onChange={onChangeHandler} />
</label>
<div className="display">
<p>나의 나라는 {myCountry}</p>
<p>나의 도시는 {myCity}</p>
</div>
<Child func={onChangeHandler} />
</>
);
};
export default App;
//Child.js
// props로 전달되는 onChangeHandler함수가
// 메모이제이션잘되는지 확인하기위한 컴포넌트
import React, { memo } from "react";
const Child = memo(() => {
console.log("Child rendered");
return <div></div>;
});
export default Child;
onChangeHandler
함수만 받고(reference) memo로 최적화가 되어있다.useCallback과 useMemo의 남용은 좋지않다. -
최적화를 하려고 썼는데 오히려 메모이제이션되는 비용이 더 비쌀수도 있다.
나도 불필요한 컴포넌트의 리랜더링을 막으려고 useCallback을 남용했다.
직접 브라우저위에서 성능 테스트를 하지도 않은채..
무조건적으로 기술을 받기보단 그 전에 한번더 생각해보는 계기가 되었다.