React.memo 란
- 리액트에서 제공하는 고차 컴포넌트 (HOC)
- Memoization 기법으로 동작한다.
- 컴포넌트가 props 로 동일한 결과를 렌더링하면, React.memo 를 호출하고 결과를 메모이징 하도록 래핑하여 경우에 따라 성능을 향상시킬 수 있다.
- React.memo 는 props 의 변화에만 영향을 준다.
( 함수 컴포넌트 안에서 구현한 state 나 context 의 변화에는 재렌더링 )
고차 컴포넌트? HOC ?
어떤 컴포넌트를 인자로 받아서 최적화된 새로운 컴포넌트를 반환해주는 함수
- 최적화된 새로운 컴포넌트는 렌더링이 될 때마다 prop check 라는 과정을 거쳐서 자신의 props 의 변화를 파악한다.
( props 가 변화가 있다고 인지하면 렌더링을 하고, 변화가 없으면 마지막으로 렌더링 되었던 결과를 재사용해서 렌더링한다. )
React.memo 꼭 필요할 때만!
- 컴포넌트가 같은 props 로 자주 렌더링이 될 때
- 컴포넌트가 렌더링이 될때마다 복잡한 로직을 처리해야할 때
React.memo 기본 구문
export default React.memo(Component);
export default memo(Component);
- Memo 를 사용할 컴포넌트를 memo 로 감싸주면 된다.
React.memo 예제
memo 만 사용한 예제
App.js
function App() {
const [parentAge, setParentAge] = useState(0);
const [childAge , setChildAge] = useState(0);
const incrementParentAge = () => {
setParentAge(parentAge + 1)
}
const incrementChildAge = () => {
setChildAge(childAge + 1)
}
console.log("부모 요소 업데이트")
return (
<div>
<h1>부모</h1>
<p>age : {parentAge}살</p>
<button onClick={incrementParentAge}>부모 나이 증가</button>
<button onClick={incrementChildAge}>자녀 나이 증가</button>
<Child name={"홍길동"} age={childAge}/>
</div>
);
}
- 부모 나이가 업데이트가 된다면 자식 컴포넌트 (Child) 도 같이 렌더링이 된다. 그 문제를 막기 위해서 Child 의 props 가 바뀔 때만 Child 컴포넌트가 렌더링 될 수 있도록 해주었다.
Child.jsx
import React, { memo } from "react";
const Child = ({ name, age }) => {
console.log("자식 요소 업데이트");
return (
<div>
<h3>자녀</h3>
<p>name : {name}</p>
<p>age : {age}살</p>
</div>
);
};
export default memo(Child);
useMemo 를 같이 사용한 예제
function App() {
const [parentAge, setParentAge] = useState(0);
const incrementParentAge = () => {
setParentAge(parentAge + 1)
}
console.log("부모 요소 업데이트")
const name = useMemo(() => {
return {
lastName : "홍",
firstName : "길동"
}
}, [])
return (
<div>
<h1>부모</h1>
<p>age : {parentAge}살</p>
<button onClick={incrementParentAge}>부모 나이 증가</button>
<Child name={name} />
</div>
);
}
- useMemo 글에서 보았다 싶이, 객체타입은 계속 메모리 주소가 변경되기 때문에, 메모이제이션이 되지 않아서, useMemo 를 사용해서 값을 메모이제이션 해주어야한다.
- 결론은 객체인 name 을 props 로 받아서 React.memo 를 사용해도, 객체타입이기 때문에 App.js 가 렌더링 될 때마다 name 의 메모리 주소가 변경되어서 새로 생성되기때문에 useMemo 를 사용해서 메모이제이션 시켜줘야한다.
useCallback 을 같이 사용한 예제
App.js
function App() {
const [parentAge, setParentAge] = useState(0);
const incrementParentAge = () => {
setParentAge(parentAge + 1)
}
console.log("부모 요소 업데이트")
const tellMe = useCallback(() => {
console.log("길동아 사랑해")
}, [])
return (
<div>
<h1>부모</h1>
<p>age : {parentAge}살</p>
<button onClick={incrementParentAge}>부모 나이 증가</button>
<Child name={"홍길동"} tellMe={tellMe}/>
</div>
);
}
- tellMe 함수를 useCallback 으로 묶어주지 않는다면, App.js 가 렌더링될 때마다 tellMe함수가 재 생성되기 때문에 props 가 바뀌었다고 인지해 자식 요소 (Child) 컴포넌트까지 렌더링이 되버린다.
- 결론은 tellMe 의 함수를 useCallback 을 사용해서 메모이제이션을 해줘서 props가 바뀌지 않았다는 걸 인지하게 해주어야한다.
Child.jsx
import React, { memo } from "react";
const Child = ({ name, tellMe }) => {
console.log("자식 요소 업데이트");
return (
<div>
<h3>자녀</h3>
<p>이름 : {name}</p>
<button onClick={tellMe}>엄마 나 사랑해?</button>
</div>
);
};
export default memo(Child);
'React > 이론공부' 카테고리의 다른 글
React의 가상돔 (Virtual DOM) (0) | 2023.01.25 |
---|---|
React.Fragment (0) | 2023.01.25 |
[React Hooks] useReducer (0) | 2023.01.25 |
[React Hooks] useCallback (0) | 2023.01.25 |
[React Hooks] useMemo (0) | 2023.01.24 |