Frontend/React

React 리액트 - useMemo()

Ayel 2025. 12. 23. 20:26

 

 

memoization

 

 

memoization(메모이제이션)

: 함수형 컴포넌트에서 다른 변화 때문에 연산이 되는 불필요한 연산을 하지 않기 위해 사용

 

useMemo()

: 메모리에 있는 캐시를 사용하는 함수

 

- 캐시에 있는 것을 사용한다는 것은 최초에 마운트를 할 때 연산결과를 캐시에 담아놓고

리랜더링이 있을 때 캐시와 결과를 비교하고, 내가 원하는 값의 변화를 줄 때만 연산을 수행한다

이것을 memoization이라고 한다

 

 

ProductContainer

 

 

<Product> 컨테이너

import React, { useCallback, useMemo, useState } from 'react';
import Amount from './Amount';

const ProductContainer = () => {
  const containerStyle = {
      width: "500px",
      height: "300px",
      margin: "20px auto"
  }

  const productStyle = {
      border: "1px solid lightgray", padding: "30px", lineHeight: "1.3"
  }

  const divStyle = {
      border: "1px solid blue",
      height: "60px",
      display: "flex",
      justifyContent: "space-evenly",
      alignItems: "center",
      marginTop: "20px",
      padding: "20px",
  };

  const pStyle = {
      lineHeight: "0",
  };

  const buttonStyle = {
      width: "40px",
      height: "40px",
  }

  console.log("부모 랜더링 🫅")

  const [like, setLike] = useState(0)
  const [amount, setAmount] = useState(0)
  const [coupon, setCoupon] = useState(0)

  const amountMemo = useMemo(() => {
    console.log("amount 연산")
    return amount
  }, [amount])

  const couponMemo = useMemo(() => {
    console.log("coupon 연산")
    return coupon
  }, [coupon])
  // 캐시값을 저장하기 위해 amount와 coupon을 분리해서 사용

  const props = {amount: amountMemo, coupon: couponMemo}

  const handleAddAmountOnClick = useCallback(() => {
    setAmount(amount +1)
  }, [amount]) // 의존성배열은 amount를 동작하기 때문에 배열에 amount를 넣어준다
  const handleSubtractAmountOnClick = useCallback(() => {
    setAmount(amount -1)
  }, [amount])
  const handleAddCouponOnClick = useCallback(() => {
    setCoupon(coupon +1)
  }, [coupon]) 
  const handleSubtractCouponOnClick = useCallback(() => {
    setCoupon(coupon -1)
  }, [coupon])

  return (
    <div style={containerStyle}>
      <div style={productStyle}>
        <p>
          [책] 배워서 바로 써먹는 리액트
        </p>
        <button onClick={() => {setLike(like +1)}}>좋아요👍{like}</button>
        <Amount
          props={props}
          pStyle={pStyle}
          divStyle={divStyle}
          button={buttonStyle}
          handleAddAmountOnClick={handleAddAmountOnClick}
          handleSubtractAmountOnClick={handleSubtractAmountOnClick}
          handleAddCouponOnClick={handleAddCouponOnClick}
          handleSubtractCouponOnClick={handleSubtractCouponOnClick}
        />
      </div>
    </div>
  );
};

export default ProductContainer;

 

 

: useCallback은 “함수를 메모이제이션”해서

불필요하게 새 함수가 만들어지는 걸 막아주는 Hook

 

 

<Amount> 컴포넌트

import React from 'react';

const Amount = ({
    props, 
    pStyle,
    divStyle,
    buttonStyle,
    handleAddAmountOnClick, 
    handleSubtractAmountOnClick, 
    handleAddCouponOnClick, 
    handleSubtractCouponOnClick
  }) => {

  console.log("자식 랜더링👶")
  const {amount, coupon} = props; // 구조분해 할당

  return (
    <div style={divStyle}>
      <button style={buttonStyle} onClick={handleSubtractAmountOnClick}>-</button>
      <p style={pStyle}>AMOUNT: {amount}</p>
      <button style={buttonStyle} onClick={handleAddAmountOnClick}>+</button>

      <button style={buttonStyle} onClick={handleSubtractCouponOnClick}>-</button>
      <p style={pStyle}>COUPON: {coupon}</p>
      <button style={buttonStyle} onClick={handleAddCouponOnClick}>+</button>
    </div>
  );
};

export default Amount;

 

 

<결과화면>

 

 

- 파란색이 Amount, 전체가 Container

- 부모 안에 자식이 포함되어 있는 상태

- 부모가 리랜더링되면 자식이 리랜더링된다

 

- Amount와 Coupon을 하나로 연산할 경우 Amount 하나만 동작해도

-> Amount만 리랜더링 되는 게 아니라 Coupon까지 리랜더링되는 사이드이펙트 발생

-> useMemo()로 사이드이펙트 해소

 

 

const amountMemo = useMemo(() => {
    console.log("amount 연산")
    return amount
  }, [amount])

  const couponMemo = useMemo(() => {
    console.log("coupon 연산")
    return coupon
  }, [coupon])

 

 

: 캐시값을 저장하기 위해 amount와 coupon을 분리해서 사용

 

 

 

 

- useMemo()를 사용해 amount와 coupon을 분리

-> 각각 별도로 랜더링됨

 

<결과화면>

 

 

- amount와 coupon은 각각 캐시에 들어가 있는 상태