React.memo
컴포넌트, 변수, 함수 등을 재렌더링 할 때 제어가 필요한 경우 메모이제이션을 수행합니다.
메모이제이션이란 이전 처리 결과를 저장해둠으로써 처리속도를 높이는 기술입니다.
즉, 필요할 때만 다시 계산하게 하여 불필요한 처리를 줄입니다.
컴포넌트를 메모이제이션해서 부모 컴포넌트가 재렌더링되더라도 자식 컴포넌트의 재렌더링을 방지합니다.
리액트 내의 memo를 사용하며 import를 해주어야 합니다 사용법은 컴포넌트 함수 전체를memo() 로 감싸면 됩니다.
[App.js]
import { useState, memo } from "react";
import { Child1 } from "./components/Child1";
import { Child4 } from "./components/Child4";
//TODO: React.memo
// 리액트에서 컴포넌트, 변수, 함수 등을 재렌더링할 때 제어가 필요한 경우 메모이제이션을 수행
// 메모이제이션 : 이전 처리 결과를 저장, 처리속도를 높이는 기술, 필요할 때만 다시 계산하게 하여 불필요한 처리를 줄일 수 있음
// 사용법 : const 컴포넌트명 = memo(()=>{});
// import memo from "react";
export const App = memo(() => {
// 컴포넌트를 괄호로 감싸면 해당 컴포넌트는 props에 변경이 있을 때만 재렌더링됨
console.log("App 렌더링");
const [num, setNum] = useState(0);
const onClickButton = () => {
setNum(num + 1);
};
return (
<>
<button onClick={onClickButton}>버튼</button>
<p>{num}</p>
<Child1 />
<Child4 />
</>
);
});
export default App;
[Child 1, 2, 3, 4]
import {Child2} from "./Child2";
import {Child3} from "./Child3";
import {memo} from "react";
const style = {
height : "200px",
backgroundColor : "lightblue",
padding : "8px"
};
export const Child1 = memo((props) => {
console.log("Child1 렌더링");
return (
<div style={style}>
<p>Child 1</p>
<Child2 />
<Child3 />
</div>
);
});
import {memo} from "react";
const style = {
height: "50px",
backgroundColor: "lightgray",
};
export const Child2 = memo(() => {
console.log("Child2 렌더링");
return (
<div style={style}>
<p>Child2</p>
</div>
);
});
import {memo} from "react";
const style = {
height: "50px",
backgroundColor: "lightgray",
};
export const Child3 = memo(() => {
console.log("Child3 렌더링");
return (
<div style={style}>
<p>Child3</p>
</div>
);
});
import {memo} from "react";
const style = {
height: "200px",
backgroundColor: "wheat",
padding: "8px",
};
export const Child4 = memo(() => {
console.log("Child4 렌더링");
return (
<div style={style}>
<p>Child4</p>
</div>
);
});
[실행결과]
* 상단 버튼을 누르면 부모 컴포넌트인 App 부분만 재렌더링 되는 것을 볼 수 있으며 자식 컴포넌트 Child 1, 2, 3, 4는 재렌더링 되지 않는 것을 알 수 있습니다.
useCallback
memo를 사용해 컴포넌트를 메모이제이션 할 수 있습니다.
이번에는 함수 메모이제이션을 알아봅시다!
먼저 Child1에 리셋 버튼을 생성합니다.
리셋 버튼을 클릭하면 카운트 수치를 0으로 되돌리는 기능을 추가하면 됩니다.
카운트 수치의 state는 부모 컴포넌트인 App 이 가지고 있기 때문에 App 안에서 리셋하기 위한 함수를 정의하고 그 함수를 Child1에 전달하는 방식으로 구현합니다.
[App.js]
import { useState, memo } from "react";
import { Child1 } from "./components/Child1";
import { Child4 } from "./components/Child4";
//TODO: React.memo
// 리액트에서 컴포넌트, 변수, 함수 등을 재렌더링할 때 제어가 필요한 경우 메모이제이션을 수행
// 메모이제이션 : 이전 처리 결과를 저장, 처리속도를 높이는 기술, 필요할 때만 다시 계산하게 하여 불필요한 처리를 줄일 수 있음
// 사용법 : const 컴포넌트명 = memo(()=>{});
// import memo from "react";
export const App = memo(() => {
// 컴포넌트를 괄호로 감싸면 해당 컴포넌트는 props에 변경이 있을 때만 재렌더링됨
console.log("App 렌더링");
const [num, setNum] = useState(0);
const onClickButton = () => {
setNum(num + 1);
};
// 리셋함수 정의
const onClickReset = () => {
setNum(0);
};
return (
<>
<button onClick={onClickButton}>버튼</button>
<p>{num}</p>
{/* Child1에 props로 클릭함수를 전달 */}
<Child1 onClickReset={onClickReset} />
<Child4 />
</>
);
});
export default App;
[Child1.js]
import {Child2} from "./Child2";
import {Child3} from "./Child3";
import {memo} from "react";
const style = {
height : "200px",
backgroundColor : "lightblue",
padding : "8px"
};
export const Child1 = memo((props) => {
console.log("Child1 렌더링");
// props로 부터 함수를 전개
const {onClickReset} = props;
return (
<div style={style}>
<p>Child 1</p>
{/* onClick 속성 추가하고 함수 값 넣기 */}
<button onClick={onClickReset}>리셋</button>
<Child2 />
<Child3 />
</div>
);
});
[실행결과]
그러나 앞에서 최적화했던 재렌더링을 다시 확인해보면 카운트 업 할때마다 Child1이 재렌더링 되는 것을 알 수 있습니다.
함수를 Props에 전달할 때 컴포넌트를 메모이제이션해도 재렌더링되는 것은
함수가 다시 생성되기 때문입니다. 일반적으로 우리가 함수를 정의할 때는 아래와 같이 정의합니다.
// 리셋함수 정의
const onClickReset = () => {
setNum(0);
};
이렇게 함수를 정의하면 재렌더링 등으로 코드가 실행될 때마다 항상 새로운 함수가 다시 생성됩니다.
따라서 함수를 Props로 받는 Child1 은 Props가 변화했다고 판정해 카운트업 할 때마다 재렌더링을 하게 되는 것입니다.
이 현상을 피하기 위해서는 함수에 메모이제이션을 해주어야 합니다.
리액트는 함수 메모이제이션 기능 useCallback을 제공합니다. useCallback은 첫번째 인수에 함수, 두번째 인수에 의존 배열을 받습니다.
그러면 Child1 에 리셋함수를 아래와 같이 변경해줍니다.
// 리셋함수 정의 - useCallback 함수 사용
const onClickReset = useCallback(() => {
setNum(0);
}, []);
변경 후 실행화면을 볼까요?
App 만 재렌더링되어 불필요한 재렌더링을 최적화하였습니다.
변수 메모이제이션
앞에서 컴포넌트 메모이제이션과 함수 메모이제이션에 대해 알아보았습니다.
기본적으로 이 두가지를 사용하면 불필요한 재렌더링을 제어할 수 있습니다.
React.useMemo
memo나 useCallback 만큼은 자주사용하지는 않지만 리액트에서는 변수 메모이제이션으로 useMemo를 제공합니다.
useMemo 사용법은 아래와 같습니다.
// 변수 메모이제이션
const 변수명 = useMemo(()=>{
// 실행부분 - 함수에 변수에 설정할 값의 반환
},[의존배열]);