96일차 TIL : 리액트 최적화

변시윤·2023년 2월 3일
0

내일배움캠프 4기

목록 보기
105/131
post-custom-banner

학습내용

  • React.memo
  • useCallback
  • useMemo

memoization

캐싱 대상을 기억한 후 필요할 때마다 재사용해서 불필요한 렌더링이 발생하지 않도록 최적화 하는 작업

memoization의 종류

-React.memouseCallbackuseMemo
캐싱 대상컴포넌트함수

자식 컴포넌트의 리렌더링 발생 조건
1. state가 변경되었을 때
2. props가 변경되었을 때
3. 부모 컴포넌트가 리렌더링 되었을 때


React.memo

부모 컴포넌트가 리렌더링 되었을 때 자식 컴포넌트까지 불필요하게 리렌더링 되는 일을 방지하기 위해 컴포넌트를 기억

App.jsx

const App = () => {
	const [count, setCount] = useState(0);
    
    const onPlusClick = () => {
    	setCount(count + 1);
    }
    
    count onMinusClick = () => {
    	setCount(count - 1);
    }
    
    return(
    	<>
        	<h3>{count}<h3>
            <button onClick={onPlusClick}>+</button>
            <button onClick={onMinusClick}>-</button>
            <Box1 />
            <Box2 />
            <Box3 />
        </>
    );
 
}

위 예제에서 +,- 버튼을 클릭하면 <Box /> 컴포넌트들은 state가 변하지 않았음에도 불구하고 리렌더링이 발생한다.

export default React.memo(Box1);

이 경우 자식 컴포넌트를 export 할 때 React.memo를 사용하면 해당 컴포넌트를 기억하기 때문에 불필요한 리렌더링이 일어나지 않는다. 혹은 아래와 같이 사용할 수도 있다.

import { memo } from "react";
.
.
.
export default memo(Box1);

단, React.memo가 모든 경우에 적용되는 것은 아니다. 자식 컴포넌트가 가벼운 작업을 수행할 경우에는 사용하지 않는 것이 성능면에서 좋다.


useCallback

함수의 내용은 변하지 않았으나 주소값이 변경돼서 props 변경으로 불필요한 리렌더링이 일어나는 일을 방지하기 위해 함수를 기억

<Box1/> 안에 count를 초기화 하는 버튼을 생성하고 초기화를 실행 시키는 함수 initCount()를 App.jsx에서 내려준다고 가정해보자. 초기화 버튼을 실행하면 App과 Box1이 모두 리렌더링 된다. 부모 컴포넌트가 리렌더링 됨에 따라 발생한 리렌더링은 React.memo로 방지하고 있기 때문에 이 경우엔 props가 변경된 경우에 해당한다.

const initCount = () => {
	setCount(0);
};

props로 받아오고 있는 initCount는 변하지 않는 함수다. 그러나 함수는 객체에 해당한다. 자바스크립트는 객체 저장시 객체의 내용이 아니라 주소를 저장한다. 그래서 내용이 같은 두 객체가 있다면 그 둘은 실제로 다른 객체에 해당된다. 마찬가지로 App이 렌더링 될 때마다 initCount를 다른 주소에 할당하고 있기 때문에 Box1에서 리렌더링이 일어나는 것이다.

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

이처럼 함수의 내용이 변하지 않는 경우 위와 같이 useCallback을 사용하면 불필요한 리렌더링을 방지할 수 있다. 단, 최초 렌더링시 저장된 값만을 기억하기 때문에 특정 값이 변화할 때마다 반영하기 위해선 useEffect와 마찬가지로 의존성 배열에 해당 state를 추가한다.


useMemo

객체, 배열, 함수의 값을 저장해서 불필요한 작업 방지

Box2.jsx

const Box2 = () => {
	const [count, setCount] = useState(0);

	const heavyWork = () => {
    	for(i = 0; i < 5000000000; i++){
    	//
    	}
    	return 100;
    };
	
    const value = heavyWork();
    
    return(
    	<>
        	<h2>{value}</h2>
            <button onClick={() => {setCount(count+1);}}>클릭</button>
            <p>{count}></p>
        </>
    );
}

count가 변할 때마다 heavyWork를 실행한다. 그러나 heavyWork는 늘 100을 return 하기 때문에 매번 실행을 할 필요가 없으므로 불필요한 작업이 발생한다.

const value = useMemo(() => heavyWork(), []);

useMemo를 사용하면 최초 렌더링시에만 값을 저장해서 불필요한 작업을 방지할 수 있다. 마찬가지로 의존성 배열을 사용한다.

profile
개그우먼(개발을 그은성으로 하는 우먼)
post-custom-banner

0개의 댓글