메모이제이션 in React

Yuno·2021년 12월 31일
0
post-thumbnail

💡 메모이제이션: 프로그램이 동일한 계산을 반복해야할 때, 이전 값을 메모리에 저장하고, 동일한 계산의 반복수행을 제거한다. (메모라이즈 memorized)

FE의 성능의 대부분은 (아마 DOM 렌더링)에서 소비될 것

💡 react는 state & props의 변화에 따라 렌더링된다.

📄 (state의 변화 등) 컴포넌트가 렌더링 되는 상황을 effect라고 표현

useMemo

연산된 값을 useMemo 훅을 통해 재사용한다.

연관 없는 다른 effect에 의한 렌더링에는, 값을 재사용한다.

활용

Context Provider (참조 타입 전달)

Context의 상태(객체)가 (Provider)전달되는데,

객체를 작성하면, 렌더링 마다 매번 다른 값(주소)으로 취급된다.

💡 [참조 타입] 전달 시 유의 (Reference type ←→ primitive type)

때문에, 모든 effect에 의한 렌더링마다, 하위 컴포넌트가 다시 렌더링 된다.

useMemo로 저장하여, 다른 effect에 의한 렌더링에는 context value가 변하지 않는다.

다른 경우

state를 그대로(혹은 계산후에) 전달한다면, state가 변하면 렌더링 하는게 맞다.

그러나, 다른 effect에 의하여 렌더링 될 때는, 값을 다시 계산할 필요는 없다. (재사용 필요)

const value = useMemo(()=>calcComplex(users), [users]);

users로 인한 effect에만, 함수를 실행시켜 값을 계산하고, 기억한다.

실제 활용

// 다른 effect에는 함수를 실행하지 않고, 기존 dpt값을 사용한다.
const dpt = useMemo(() => dpTitle(title), [title]);

return <span>{dpt}</span>

React.memo()

React는 고차컴포넌트 React.memo()를 제공한다.

렌더링 결과를 메모라이징 하여, 불필요한 리렌더링을 건너뛴다.

💡 고차 컴포넌트: 컴포넌트를 값으로 활용한다.

만약, 성능적으로 이점을 얻지 못한다면 사용하지 않는 것이 좋다.

쓸모없는 props 비교 때문

memo와 콜백 함수

자식에게 함수를 보내준다면, props 비교에 주의 해야한다.

💡 참조 타입과 같은 비교 원칙을 따른다 (Reference 비교)

렌더링 마다 새로운 콜백 때문에, Child는 항상 리렌더링 된다.

때문에, useCallback()을 활용하여 콜백의 인스턴스를 보존해야한다.

const resetCount = useCallback(() => {
    setCount(0);
  }, [])

return (
	<Child 
    value={value}
    resetCount={resetCount}
  />
)

Child가 value의 변화에만 렌더링된다. (메모라이즈 컴포넌트 일 때)

예시

1️⃣ memo() 활용 Component 메모라이즈

//React.memo()
const Child = React.memo(({ value }) => {
	return <div>{value}</div>
})

const App = () => {
	const [cnt, setCnt] = useState(0);
	const [another, setAnother] = useState(false);

	const value = complexCalc(cnt);

	return (
		<Child value={value} />	
	)	
}
export default App;

Child 컴포넌트가 메모라이즈 되었다.

another state에 의한 effect에 대해, 렌더링 하지 않지만, complexCalc는 매번 실행된다.

2️⃣ useMemo활용 value 메모라이즈

const Child = ({ value }) => {
	return <div>{value}</div>
}

const App = () => {
	const [cnt, setCnt] = useState(0);
	const [another, setAnother] = useState(false);

	const value = useMemo(()=>complexCalc(cnt), [cnt]);

	return (
		<Child value={value} />	
	)	
}
export default App;

cnt 변화에 의한 effect에만 complexCalc가 실행된다. 의미없는 연산 낭비를 막을 수 있다.

그러나, Child 컴포넌트는 anothereffect에도 렌더링 된다.

profile
web frontend developer

0개의 댓글