React에서 불필요한 렌더링을 방지하고 성능을 최적화하는 방법
: useMemo, useCallback, memo
전체 컴포넌트가 호출 되었을 때 ...
const 저장할_호출결과명 = useMemo( ( ) => {
return 콜백함수_코드
}, [ 값 ] )
import { useMemo, useState } from 'react'
import './App.css'
function App() {
const [number, setNumber] = useState(0);
const [rerender, setRerender] = useState(false)
// 콘솔 확인 때문에 case1 코드로 사용 case2 코드로 사용하여도 무방
// ▪️ Case : 1
const plus1 = (n) => {
console.log('plus1 실행됨')
return n + 1
}
// ▪️ Case : 2
// const plus1 = (n) => n + 1
// 🔽 [] 안의 값이 변경되었을 때 useMemo (() => {이 함수를 호출하겠다.},[])
// ▪️ useMemo 적용 전 : " Rerender " 버튼 클릭 시 App 컴포넌트 리렌더링 => console.log('plus1 실행됨') 실행
// ▪️ useMemo 적용 후 : [number] 값이 바뀌었을 때만 {numberPlus1} 함수 호출, 화면 값 변경
// 만약, [rerender] 를 넣고, Rerender 버튼 클릭 -> console.log('plus1 실행됨') 실행, {numberPlus1} 함수 호출
// number + 1 버튼 클릭 -> 기본 number 값만 변경되고, numberPlus1 함수 값이 변경되지 않음. 예시 : number + 1 버튼 3번 클릭 후 Rerender 버튼 클릭 시 numberPlus1 값이 변경 되어 +3 된 값이 화면상에 렌더링
const numberPlus1 = useMemo(() => {
return plus1(number)
}, [number])
return (
<>
{/* 🔽 여기서 처음 실행한 함수가 numberPlus1 : plus1(number) 이므로 첫 렌더링 때 1로 나옴 */}
<div> numberPlus1 : {numberPlus1} </div>
<button onClick={() => {setNumber(number + 1)}}> number + 1</button>
<button onClick={() => {setRerender(!rerender)}}>Rerender</button>
</>
)
}
export default App
컴포넌트가 호출 되었을 때 ...
const 저장할_함수 = useCallback( ( ) => {
return 콜백 함수 코드
}, [ 값 ] )
import { useCallback, useEffect, useMemo, useState } from 'react'
import './App.css'
function App() {
const [number, setNumber] = useState(0);
const [rerender, setRerender] = useState(false)
// ▪️ 빈배열이면 처음 렌더링 될 때만 !
const plus1 = useCallback(
(n) => {
console.log('plus1 실행됨')
return n + 1
}, [] )
useEffect(() => {
console.log("plus1 생성됨 / 이 곳에 무거운 작업이 수행될 때 사용하기 유리하다 !")
}, [plus1])
const numberPlus1 = useMemo(() => {
return plus1(number)
}, [number])
return (
<<>
<div> numberPlus1 : {numberPlus1} </div>
<button onClick={() => {setNumber(number + 1)}}> number + 1</button>
<button onClick={() => {setRerender(!rerender)}}>Rerender</button>
</>
)
}
export default App
useCallback()useEffect()컴포넌트를 호출해야 할 때 ...
const 저장할_컴포넌트 = memo( ( props ) => {
함수 컴포넌트 코드
} )
import { memo, useCallback, useEffect, useMemo, useState } from 'react'
import './App.css'
// ▪️ memo 선언
const NumberDisplay = memo(({ number }) => {
console.log('Display 렌더링');
return <div> number: {number} </div>;
});
function App() {
const [number, setNumber] = useState(0);
const [rerender, setRerender] = useState(false)
const plus1 = useCallback(
(n) => {
console.log('plus1 실행됨')
return n + 1
}, [number] )
useEffect(() => {
console.log("plus1 생성됨")
}, [plus1])
const numberPlus1 = useMemo(() => {
console.log('numberPlus1 변경')
return plus1(number)
}, [number])
return (
<>
<NumberDisplay number={number}/>
<div> numberPlus1 : {numberPlus1} </div>
<button onClick={() => {setNumber(number + 1)}}> number + 1</button>
<button onClick={() => {setRerender(!rerender)}}>Rerender</button>
</>
)
}
export default App
{props} 로 들어간 값이 변경 되어야 컴포넌트 재선언 [의미]
| 값이 불변(Immutable)하고, 직접 데이터를 저장하는 타입
| 변수를 복사하면 값이 그대로 복사됨 (값 복사, Call by Value)
[종류]
number, string, boolean, null, undefined, symbol, bigint
[특징]
[기본 예제]
const memo1 = "park"
const memo2 = "park"
console.log(memo1 === memo2)
=> true
[의미]
| 여러 개의 값을 저장할 수 있는 컨테이너. 메모리 주소(참조 값)를 저장
| 변수를 복사하면 참조가 복사됨 (참조 복사, Call by Reference)
[종류]
Object, Array, Function, Date •••
[특징]
[기본 예제]
const memo1 = {
name: "park"
}
const memo2 = {
name: "park"
}
console.log(memo1 === memo2)
=> false
import { useEffect, useMemo, useState } from 'react'
import './App.css'
function App() {
const [number, setNumber] = useState(0)
const [isKorea, setIsKorea] = useState(true)
// CASE : 1
const country = useMemo(() => {
return{
location: isKorea ? "한국" : "외국"
}
}, [isKorea ])
// CASE : 2
// const country = isKorea ? "한국" : "외국"
// CASE : 2 처럼 원시 데이터를 사용하면 useMemo로 묶어주지 않아도 useEffect에서 country 값이 변하지 않는다고 생각해서 console.log("오래 걸리는 작업 ...") 이 작동하지 않지만,
// CASE : 1 처럼 배열이나 객체인 객체 데이터를 사용하면 주소 값이 변하므로 변경된다고 생각하여 작업이 진행된다.
// useEffect 에서 오래 걸리는 작업이 필요하다면 위에 useMemo 를 써주는 것이 좋다
useEffect(() => {
console.log("오래 걸리는 작업 ...")
}, [country])
return (
<>
<h3> 하루에 몇끼 먹어요 ? </h3>
<input
type='number'
value={number}
onChange={(e) => setNumber(e.target.value)}></input>
<br/>
<h3> 어느 나라에 있어요 ? </h3>
<div> 나라 : {country.location}</div>
<button onClick={() => setIsKorea(!isKorea)}>비행기 타자</button>
</>
)
}
export default App
: React 컴포넌트 구조를 시각적으로 탐색하고, props, state, hooks 등을 실시간으로 확인하고 변경 가능

[설치 후 사용 방법]
F12 (개발자 도구) 실행⚛️ Components 탭과 ⚡ Profiler 탭이 추가됨Components 탭에서 컴포넌트 트리 확인 가능