[React] useMemo, useCallback

Jnary·2024년 4월 30일
0

React

목록 보기
6/10
post-thumbnail

메모이제이션

메모이제이션이란?

  • Memoization
  • 컴퓨팅에서 비용이 많이 드는 계산의 결과를 저장하여 후속 호출에서 빠르게 결과를 반환할 수 있게 하는 최적화 기술
  • 동일한 입력에 대해 함수가 여러번 호출될 때 특히 우용
  • 중복 계산 방지 → 애플리케이션 성능 향상
  • useMemo useCallback : 메모이제이션을 통해 컴포넌트의 성능을 최적화하는 데 사용되는 훅

메모이제이션 작동 원리

  • 캐시 데이터 구조 사용
  • 이전에 계산된 입력값과 그 결과를 저장
  • 함수 호출 시, 캐시 확인하여 해당 입력값에 대한 결과가 이미 저장되어있는지 검사
    • 캐시 있으면 → 저장된 결과 바로 반환
    • 없으면 → 계산 수행, 그 결과를 캐시에 저장 후 결과 반환

메모이제이션 예시

  • 피보나치 수열 계산
    • 순수한 재귀함수로 구현할 경우 매우 비효율적

    • 메모이제이션으로 최적화

      def fibonacci(n, memo={}):
          if n in memo:
              return memo[n]
          if n <= 2:
              return 1
          memo[n] = fibonacci(n-1, memo) + fibonacci(n-2, memo)
          return memo[n]

메모이제이션 장점

  1. 성능 향상
    • 중복 계산 방지
    • 함수의 실행 시간 감소
  2. 효율성
    • 반복적이고 중첩된 함수 호출에 유리
    • 복잡한 알고리즘의 성능 개선 가능

메모이제이션 단점

  1. 메모리 사용량 증가
    • 계산 결과를 저장하기 위해 추가 메모리 사용
  2. 오버헤드
    • 모든 경우에 유용 X
    • 캐시 관리에 따른 추가적인 오버헤드 발생 가능

useMemo

useMemo

  • 비용이 많이 드는 함수의 결과값을 메모리에 저장
  • 의존성 배열에 있는 값이 변경될 때만 함수를 다시 실행하여 값을 계산
  • 의존성 배열에 있는 값 변경없을 때는, 이전에 메모리에 저장된 값 재사용

useMemo 사용법

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

useEffect? useMemo?

이번 과제에서 useEffect와 useMemo 사용 관련해서 비교한 부분 정리

const CardTable = ({ cnt }) => {
  const [clickedId, setClickedId] = useState(-1);
  const cardItems = randomUtil(cnt);
  • 문제: clickedId 가 state이기 때문에 해당 값이 바뀔 때마다 CardTable 전체가 리렌더링 된다.
const CardTable = ({ cnt }) => {
  const [clickedId, setClickedId] = useState(-1);
  let cardItems = [];
  useEffect(() => {
    cardItems = randomUtil(cnt);
  }, [cnt]);
  • useEffect는 CardTable 전체가 렌더링된 이후 cnt 값이 변경됐을 때만 호출된다.
  • 값을 반환하지 않는다.
  • cardItems를 변경하였더라도 return(jsx)에 반영되지 않는다.
  • useEffect를 사용하려면 cardItems를 상태로 만들어주어야 한다.
const CardTable = ({ cnt }) => {
  const [clickedId, setClickedId] = useState(-1);
  const cardItems = useMemo(() => {
    return randomUtil(cnt);
  }, [cnt]);
  • useMemo는 CardTable 전체가 렌더링되는 것과 상관없이 cnt 값을 유지하고 있다.
  • 리렌더링될 때, 기존에 유지하고 있던 cnt값과 현재의 cnt값을 비교하고, 변경됐을 때만 호출된다.
  • 반환값을 해당 함수 블록에서 사용 가능하다. → return(jsx) 에서도 반환값 사용이 가능하다.

useCallback

useCallback

  • 특정 함수를 메모리에 저장
  • 의존성 배열에 있는 값이 변경될 때만 함수를 다시 생성
  • 주로 불필요한 렌더링 방지

useCallback 사용법

const memoizedCallback = useCallback(() => {
  doSomething(a, b);
}, [a, b]);
  • doSomething : 호출 함수
  • a b : 함수가 의존하는 변수 → a, b가 변경되지 않는 한, 같은 함수 참조를 유지

useMemo vs. useCallback

useMemouseCallback
사용 의도값의 메모이제이션을 위해 사용함수 자체의 메모이제이션을 위해 사용
반환값결과값 반환함수 자체 반환
재사용성계산된 값의 재사용 목적특정 함수의 재사용 목적
자식 컴포넌트와의 상호작용자식 컴포넌트에 props로 함수를 전달할 때 유용 → 같은 함수 참조 유지함으로써 자식 컴포넌트가 불필요하게 리렌더링 되는 것 방지
  • 두 훅 모두 의존성 배열의 값을 기준으로 업데이트 여부 결정
  • 의존성 관리가 중요 → 잘못 관리된 의존성은 예상치 못한 버그를 일으킬 수 있음
    import React, { useState, useMemo } from 'react';
    
    function PriceCalculator({ quantity, pricePerItem }) {
      const [discount, setDiscount] = useState(0);
    
      const totalPrice = useMemo(() => {
        return quantity * pricePerItem * (1 - discount);
      }, [quantity, pricePerItem]); // discount가 누락되었음
    
      return (
        <div>
          <h1>Total Price: ${totalPrice.toFixed(2)}</h1>
          <button onClick={() => setDiscount(0.1)}>Apply 10% Discount</button>
        </div>
      );
    }
    • useMemoquantitypricePerItem에 의존하여 총 가격을 계산

    • discount 변수가 의존성 배열에서 누락

    • "Apply 10% Discount" 버튼을 클릭하여 할인율을 적용하더라도, useMemodiscount의 변화를 감지하지 못해 총 가격 업데이트 X

      const totalPrice = useMemo(() => {
        return quantity * pricePerItem * (1 - discount);
      }, [quantity, pricePerItem, discount]); // discount를 의존성 배열에 추가
      
profile
숭실대학교 컴퓨터학부 21

7개의 댓글

comment-user-thumbnail
2024년 5월 1일

메모이제이션이 뭔지 정도만 알고 있었는데 장단점과 작동 원리들을 간단하고 이해하기 쉽게 정리해줘서 이해하면서 읽는데 많은 도움이 됐습니다! 그리고 저도 카드를 섞고 리턴해주는 과정에서 계산하는 비용이 조금 많이 들 수도 있겠다 생각했는데 이번 과제에 useMemo를 적용해주신 부분 너무 좋은 시도 같아요!!! 배워갑니다 ㅎㅎ
의존성 배열을 설정할 때 주의해야하는 부분도 예시를 통해 너무 잘 정리해주셨네요! 유용한 아티클 잘 보구 갑니다 고생하셨어요!

답글 달기
comment-user-thumbnail
2024년 5월 1일

메모이제이션에 대해서 자세하게 설명해 주셔서 너무 읽기 좋았습니다...!! 특히 피보나치처럼 익숙한 예제로 설명해 주셔서 더 이해하기 좋았어요 ✨ useMemo 부분도 이번 과제와 연결해서 설명해 주셔서 공감하면서 읽었습니다... 저도 state가 바뀔 때마다 리렌더링 되는 부분에서 고민을 많이 했는데 useMemo로 해결하신 거 너무 좋네요!! 🔥 깔끔한 아티클 잘 읽었습니다 감사합니다!

답글 달기
comment-user-thumbnail
2024년 5월 1일

메모이제이션을 활용하는 예시로 피보나치를 들어주셔서 DP도 떠오르고, 더욱 많은 지식들을 연결할 수 있었던 것 같습니다 👍 무엇보다 헷갈릴 수 있는 useEffect VS useMemo, useCallback VS useMemo 등을 설명해주셔서 개념을 한번 더 단단히 다지고 갈 수 있었던 아티클이었습니다 ㅎㅎ
좋은 아티클 감사합니다!

답글 달기
comment-user-thumbnail
2024년 5월 1일

useMemo와 useCallback 이 두 훅의 차이점과 정확한 사용 시나리오를 항상 명확하게 파악하지 못했는데, 이번 기회에 그 차이를 분명히 이해할 수 있게 되었습니다! useMemo가 계산된 값의 메모이제이션을 위해 사용되고, useCallback은 특정 함수 자체의 메모이제이션을 위해 사용된다는 부분이 이해하기 어렵다고만 생각했었는데, 실제로는 각각의 훅이 갖는 목적과 사용 사례가 분명하다는 것을 알게 되었습니다!
메모이제이션 훅들의 작동 원리를 설명하는 부분도 잘 정리되어 있어서 좋았어요! 특히, useMemo의 의존성 배열에서 discount가 누락된 예시부분에서, 실제 개발 과정에서 할 수 있는 실수(?)를 잘 설명해 주고있어서, 이를 통해 useMemo의 의존성 배열 관리가 얼마나 중요한지 깨달았습니다!

답글 달기
comment-user-thumbnail
2024년 5월 1일

깔끔하게 정리해주신 덕분에 useMemo, useCallback에 대해 잘 이해하게 되었습니다!
각 개념마다 코드를 통해 설명해주신 덕분에 쉽게 이해했습니다 😊 적용하기 좋은 예시들까지 설명해주신 덕분에 각 상황에 맞게 적용하여 사용할 수 있겠네요!
좋은 글 감사합니다 !

답글 달기
comment-user-thumbnail
2024년 5월 1일

useMemo, useCallback에 대해서 자세하고 알기 쉽게 설명해주셔서 이해가 바로 갔습니다!!
친절한 개념에 코드 예시도 같이 보여주셔서 확실하게 알게 되고 언제 어떻게 써야 하는지에 대해 자세히 배웠습니다! 또 메모이제이션 부분을 상세하게 조사하시고 설명해주셔서 넘 잘 봤습니다!
수고하셨어요 :)

답글 달기
comment-user-thumbnail
2024년 5월 1일

메모이제이션에 대한 개념을 자세히 몰랐는데 전체적인 개념을 잡기 쉽게 아티클 작성해주셔서 전체적인 그림 잘 잡고갑니다! 과제에 직접 useMemo 적용한거 써주신게 활용방법이 잘 와닿아서 좋았어요!! 또 메모이제이션의 개념을 사용하는 useMemo와 useCallback 훅함수 각각의 용도와 차이점을 잘 정리해주셔서 확실하게 이해하고 넘어갑니다~ 깔끔한 아티클 잘 읽고갑니다 수고하셨습니다!!!

답글 달기