Memo
React에서는 컴포넌트의 state가 변경될 경우, 해당 컴포넌트가 리렌더링 된다. 부모 컴포넌트가 렌더링이 되면 자식 컴포넌트도 렌더링이 되면서 불필요한 렌더링이 발생한다. Memo를 사용하게 되면, 이와 같은 불필요한 렌더링을 방지하는데 도움이 되어 성능을 개선시킬 수 있다. 그러나 자주 변경되는 props에 대해 memo를 사용하게 되면 memorization( 이전 값을 메모리에 저장해 동일한 계산의 반복을 제거해 빠른 처리를 가능하게 하는 기술 ) 과정에서 리소스가 발생하기 때문에 오히려 성능이 저하될 수 있다.
- const 컴포넌트명 = memo(() => { return () });
// Outer.jsx
import { useState } from "react";
import Inner from "./Inner";
const Outer = () => {
const [num, setNum] = useState(0);
const [text, setText] = useState("");
return (
<div>
<Inner num={num}/>
<button onClick={() => setNum(cnt => cnt + 1)}> 증가 </button>
<p>현재 글자 : {text} </p>
<input type="text" onChange={(e)=>setText(e.target.value)}/>
</div>
)
}
export default Outer;
// Inner.jsx
import { memo } from "react";
const Inner = memo(({ num }) => {
return (
<div>
<p> 현재 숫자 : {num} </p>
</div>
);
})
export default Inner;
Outer.jsx의 "text" state가 변경되면서 렌더링이 되었지만, Inner.jsx는 memo에 의해서 렌더링이 되지 않은 모습을 볼 수 있다.
만약 memo를 사용하지 않는다면 부모 컴포넌트가 렌더링이 될 때 자식 컴포넌트도 렌더링이 되는 모습을 볼 수 있다.
useMemo
Memo의 경우에는 컴포넌트 자체를 감싸서 사용하며, props가 변경될 때마다의 불필요한 렌더링을 방지하고자 할 때 사용하고 useMemo의 경우에는 특정 값이 변경될 때마다 새로 계산해야하는 상황에서 사용한다. useMemo의 경우 간단한 값이나 자주 변경되는 값에 사용할 경우 오히려 성능을 저하시킬 수 있다.
- useMemo([연산을정의하는함수], [검사할특정값을담은배열]);
// Inner.jsx
import { useMemo } from "react";
export default function Inner({ num, text }) {
const getNumber = num => {
console.log("숫자가 변동되었습니다.");
return num;
}
const getText = text => {
console.log("글자가 변동되었습니다.");
return text;
}
// num이 변경될 때 getNumber 시행
const shownum = useMemo(() => getNumber(num), [num]);
// text가 변경될 때 getText 시행
const showText = useMemo(() => getText(text), [text]);
return (
<div>
<p>{shownum}</p>
<p>{showText}</p>
</div>
);
}
useMemo 사용해서 num이 변경될 때만 getNumber 함수가 호출되고, text가 변경될 때만 getText함수가 호출되는 모습을 볼 수 있다.
useMemo를 사용하지 않으면 아래와 같이 getNumber와 getText가 둘다 호출되는 모습을 볼 수 있다.
useCallback
useCallback은 특정 함수를 메모리제이션하여 재사용할 수 있도록 도와준다. 의존성 배열이 변경되지 않는 한, useCallback은 항상 같은 함수를 반환한다. 주로 자식 컴포넌트에 함수를 전달할 때 불필요한 렌더링을 방지하기 위해 사용한다.
- useCallback([재사용할함수], [검사할특정값을담은배열])
// Outer.jsx
import { useState, useCallback } from 'react';
import Inner from './Inner';
const Outer = () => {
const [count, setCount] = useState(0);
// useCallback을 사용하여 handleClick 함수를 memorization
const handleClick = useCallback(() => {
setCount(cnt => cnt + 1);
}, []); // 의존성 배열이 비어 있으므로, 항상 같은 함수를 반환
return (
<div>
<h1>Count: {count}</h1>
<Inner onClick={handleClick} />
</div>
);
};
export default Outer;
import { memo } from "react";
// Inner.jsx
// memo를 사용하여 {onClick}이 변경되지 않으면 렌더링 되지 않도록 함
const Inner = memo(({ onClick }) => {
console.log("Inner 컴포넌트 렌더링");
return (
<button onClick={onClick}>
증가
</button>
);
});
export default Inner;
버튼을 눌러 숫자가 변경되었어도, handleClick 함수는 변경되지 않기 때문에 Inner 컴포넌트는 한번만 렌더링이 되는 모습을 볼 수 있다.
만약 handleClick 함수에 useCallback()이 없을 경우에는, handleClick 함수가 계속해서 변경이 되기 때문에 Inner 컴포넌트도 계속해서 렌더링 되는 모습을 볼 수 있다.
Automatic Batching
React에서는 상태의 set 함수가 연속으로 실행될 경우, 원래는 각 상태 업데이트마다 재렌더링이 발생했었다. 그러나 React v18부터는 Automatic Batching 기능이 도입되어 여러 상태가 변경되더라도 단 한 번의 렌더링으로 모든 업데이트를 반영하게 되었다. 이로 인해 렌더링 횟수가 감소하여 성능이 개선되었다.
'Frontend > React' 카테고리의 다른 글
React : forwardRef에 대해서 (0) | 2024.09.15 |
---|---|
React : custom hook(커스텀 훅)을 사용해보자 (0) | 2024.09.10 |
React : Redux에 대해서 알아보자 (0) | 2024.09.09 |
React : Context API에 대해서 알아보자 (0) | 2024.09.06 |
React : Lazy import을 통한 성능 개선 (0) | 2024.09.05 |
React: useReducer에 대해서 (0) | 2024.09.05 |
React: React에서 Styled Component 사용하기 (0) | 2024.09.04 |
React: useEffect에 대해서 (1) | 2024.09.03 |