즐코

useMemo (for 컴포넌트 최적화) 본문

React

useMemo (for 컴포넌트 최적화)

YJLEE_KR 2022. 5. 12. 01:35

useMemo

 

컴포넌트 성능 끌어올리기에 쓰인다!

 

useMemo => Memoization에서 따온 말이다.

 

메모이제이션이란!?

동일한 값을 반복적으로 호출해야한다면 맨 처음 값을 계산할 때 그 해당 값을 메모리에 저장해서 필요할 때마다 메모리에서 꺼내서 재사용하여 쓸데없이 반복되는 계산을 막아주는 기법이다. 

자주 필요한 값을 맨 처음 계산할 때 캐싱해둬서 값이 필요할 때마다 꺼내서 사용한다는 뜻

 

함수형 컴포넌트는 말그대로 함수이기 때문에 컴포넌트가 매번 렌더링 될때마다 함수가 호출되고, 그 안의 모든 변수들도 초기화 된다는 뜻이다. 따라서, 그 안에서 무의미하게 반복적으로 실행되는 값이 있다면, useMemo를 사용해서 메모이제이션을 해주면 효율적이겠다.

 

useMemo는 처음에 계산된 결과값을 메모리에 저장

-> 함수 컴포넌트가 계속 렌더링/호출되어도 useMemo안의 콜백함수는 다시 호출되지 x

-> 이미 처음에 계산해둔 값을 메모리에서 꺼내와서 재사용

 

 

useMemo(콜백함수, [상태값,변수..])

 

1- 콜백함수 : 메모이제이션해줄 값을 리턴해주는 함수

2- 의존성 배열 : 배열에 들어 있는 요소의 값이 업뎃될때만 콜백함수를 다시 호출하고 메모이제이션된 값을 업뎃,

즉 다시 메모이제이션을 해줌 

 

빈 배열 이라면? 맨처음 컴포넌트가 마운트 되었을 때만 값을 계산하고 이후에는 메모이제이션 값을 꺼내와서 사용한다.

 

const value = useMemo(()=>{
	return calculate();
},[item]);

 

 특히, 컴포넌트 내에서 useEffect 같이 변화를 감지하는 함수의 경우, 두번째 인자인 의존성 배열에 들어간 변수 타입이 중요하다.

 

1. 우선 아래처럼, location 변수가 그냥 원시타입일 경우

: 정말 location 값이 바뀌었을 경우에만, useEffect가 호출된다. (하루에 몇끼 먹었냐와 관련된 number가 바뀔땐 호출되지 않는다)

 

import { useState, useEffect } from 'react';

const Memo = () => {
  const [number, setNumber] = useState(0);
  const [isKorea, setIsKorea] = useState(true);

  const location = isKorea ? '한국' : '외국'

  useEffect(() => {
    console.log('useEffect호출')
  }, [location])

  return (
    <div>
      <h2>하루에 몇끼먹음?</h2>
      <input type="number" value={number} onChange={(e) => setNumber(e.target.value)} />
      <h2>어느 나라에 있음?</h2>
      <p>{location} 에 있습니다.</p>
      <button onClick={() => setIsKorea(!isKorea)}>비행기 타자</button>
    </div>
  )
}

export default Memo

 

2. 하지만, 이때 저 location 변수를 객체로 바꿔주면? 

: number가 바뀌어도 useEffect가 호출된다.. ㅠㅠ 

 

import { useState, useEffect } from 'react';

const Memo = () => {
  const [number, setNumber] = useState(0);
  const [isKorea, setIsKorea] = useState(true);

  const location = {
    country: isKorea ? '한국' : '외국'
  }

  useEffect(() => {
    console.log('useEffect호출')
  }, [location])

  return (
    <div>
      <h2>하루에 몇끼먹음?</h2>
      <input type="number" value={number} onChange={(e) => setNumber(e.target.value)} />
      <h2>어느 나라에 있음?</h2>
      <p>{location.country} 에 있습니다.</p>
      <button onClick={() => setIsKorea(!isKorea)}>비행기 타자</button>
    </div>
  )
}

export default Memo

 

원시타입 변수는 값이 같으면 완전히 똑같은 값으로 치지만, 

객체타입 변수는 내부 내용이 아무리 같아도, 서로가 다른 메모리 참조값, 주소값으로 저장되기 때문에 다른 변수로 여긴다. 

즉, 함수 컴포넌트가 다른 값 때문에 재렌더링, 호출이 되면 원래 객체(location)과 다른 주소값으로 메모리에 할당되기때문에,

리액트 입장에선 location이 변했다고, 바꼈다고 생각하기 때문에, useEffect 의 콜백함수가 계속 실행되는거다. 

이 때 바로 useMemo를 써주는 것이다! 

 

const a = 'react';
const b = 'react';

console.log(a===b) // true 

const aObj = { name : 'react' };
const bObj = { name : 'react' };

console.log(aObj===bObj) // false

 

useEffect에서 뭔가 오래 걸리는 작업을 해야한다면 꼭 필요할때만 호출되는 게 좋으니,

이럴 경우에만 useMemo를 적절하게 써주는 것이다. 

 

import { useState, useMemo, useEffect } from 'react';

const Memo = () => {
  const [number, setNumber] = useState(0);
  const [isKorea, setIsKorea] = useState(true);

  const location = useMemo(() => {
    return {
      country: isKorea ? '한국' : '외국'
    }
  }, [isKorea])

  useEffect(() => {
    console.log('useEffect호출')
    // 오래 걸리는 작업
  }, [location])

  return (
    <div>
      <h2>하루에 몇끼먹음?</h2>
      <input type="number" value={number} onChange={(e) => setNumber(e.target.value)} />
      <h2>어느 나라에 있음?</h2>
      <p>{location.country} 에 있습니다.</p>
      <button onClick={() => setIsKorea(!isKorea)}>비행기 타자</button>
    </div>
  )
}

export default Memo

 

출처 : https://www.youtube.com/watch?v=e-CnI8Q5RY4&t=28s

'React' 카테고리의 다른 글

useCallback (for 컴포넌트 최적화 / useMemo의 함수버전)  (0) 2022.05.12
Context API 복습  (0) 2022.05.11
useRef 복습 - 변수관리 (state와는 다르다!)  (0) 2022.05.11
useEffect 복습  (0) 2022.05.10
redux-middleware (redux-thunk)  (0) 2022.05.04
Comments