- 리액트는 컴포넌트가 재렌더링되면 거기 안에 있는 자식 컴포넌트는 항상 함께 재렌더링된다.
- 평소엔 별 문제가 없겠지만 자식 컴포넌트가 렌더링 시간이 1초나 걸리는 무거운 컴포넌트라면?
부모 컴포넌트에 있는 버튼 누를 때 마다 1초 버벅이는 불상사가 발생한다.
테스트용 자식 컴포넌트 하나 만들어보기
function Child(){
console.log('재렌더링됨')
return <div>자식임</div>
}
function Cart(){
let [count, setCount] = useState(0)
return (
<Child />
<button onClick={()=>{ setCount(count+1) }}> + </button>
)
}
- Cart 컴포넌트 안에 Child 컴포넌트를 만들었다.
- 버튼을 누를 때 Cart 컴포넌트가 재렌더링되게 만들어놧는데 이 경우 <Child> 컴포넌트도 재렌더링된다.
- 만약 <Child>가 렌더링이 2초 정도 걸리는 느린 컴포넌트라면?
=> 이럴 때 memo라는 함수를 쓰면 꼭 필요할 때만 <Child> 컴포넌트 재렌더링할 수 있다.
memo()로 컴포넌트 불필요한 재렌더링 막기
import {memo, useState} from 'react'
let Child = memo( function(){
console.log('재렌더링됨')
return <div>자식임</div>
})
function Cart(){
let [count, setCount] = useState(0)
return (
<Child />
<button onClick={()=>{ setCount(count+1) }}> + </button>
)
}
- memo() 쓰려면 'react' 라이브러리에서 import부터 해오면 된다.
- 원하는 컴포넌트 정의부분을 감싸면 된다.
- 컴포넌트를 let 컴포넌트명 = function(){} 이런 식으로 만들어야 감쌀 수 있다.
- 이제 Child로 전송되는 props가 변하거나 그런 경우에만 재렌더링된다.
- 그럼 memo는 좋은 거니까 막 써도 된다?
- memo로 감싼 컴포넌트는 헛된 재렌더링을 안 시키려고 기존 props와 바뀐 props를 비교하는 연산이 추가로 진행된다.
- props가 크고 복잡하면 이거 자체로도 부담이 될 수도 있다.
- 따라서 필요한 곳에만 사용하는 것이 좋다.
useMemo
import {useMemo, useState} from 'react'
function 함수(){
return 반복문10억번돌린결과
}
function Cart(){
let result = useMemo(()=>{ return 함수() }, [])
return (
<Child />
<button onClick={()=>{ setCount(count+1) }}> + </button>
)
}
- 반복문을 10억번 돌려야하는 경우
- 그 함수를 useMemo 안에 넣어두면 컴포넌트 로드 시 1회만 실행된다.
- useMemo는 useEffect와 비슷한 용도이다.
컴포넌트 로드 시 1회만 실행하고 싶은 코드가 있으면 거기 담으면 된다.
- 재렌더링마다 동작을 안하니 효율적으로 동작할 수 있다.
- useEffect처럼 dependency도 넣을 수 있어 특정 state, props가 변할 때만 실행할수도 있다.