본문 바로가기
FrontEnd/React.js

[React] 리액트 훅(hooks) / useMemo / useCallback

by pplucy 2023. 7. 18.

 

>> 리액트 훅 useState, useEffect 참고

https://pplucy.tistory.com/90

 

[React] 리액트 훅(hooks) / useState / useEffect

React Hook( 리액트 훅 ) : 리액트 훅이란, 함수형 컴포넌트를 지원하기 위한 기능으로 '기존에 존재하고 있던 어떠한 기능에 갈고리처럼 끼어 들어가 수행되도록 하는 것' 을 뜻한다. 기본적으로 리

pplucy.tistory.com

 

3) useMemo

 

useMemo 훅은 메모이제이션(memoization) 값을 반환하는 훅으로,

의존성 배열의 상태값이 변경되었을 경우 내부의 함수가 실행되고, 그렇지 않은 경우 기존에 메모이제이션 되었던 값을 반환하는 역할을 한다.

 

아래의 코드는 useMemo의 기본 사용법이다.

const memoizedValue = useMemo( () => {
	// 실행함수
    console.log("의존성 배열 변경");
    return value;
}, [의존성배열] )

의존성 배열이 없는 경우 컴포넌트가 렌더링 될 때마다 함수가 실행되기 때문에 의존성 배열을 추가해서 사용하여야 효율적 으로 useMemo를 사용할 수 있다. 

 

useMemo의 경우 의존성 배열의 상태값이 바뀔 때마다 로직을 실행하기 때문에 컴포넌트가 렌더링 될 때마다 불필요하게 실행되었던 계산을 방지해줄 수 있다.

 

[예제]

import {useMemo, useState} from "react";

const UseMemoHooks = () => {

	const fruits = ["딸기","바나나","메론","수박","체리"];
    const vegetables = ["당근","오이","호박","버섯","연근"];
    
    const [ fruitArray, setFruitArray ] = useState("");
    const [ vegetableArray, setVegetableArray ] = useState("");
    const [count, setCount] = useState(0);

    const changeFruits = () => {
        setFruitArray([
            ...fruitArray,
            fruits[count]
        ]);
        setCount(count < fruits.length-1? count+1 : 0);
    }

    const changeVegetables = () => {
        setVegetableArray([
            ...vegetableArray,
            vegetables[count]
        ]);
        setCount(count < vegetables.length-1? count+1 : 0);
    }

    const getVegetableLength = () => {
        // 채소의 개수를 변경하지 않아도 실행되고 있음
        console.log( "rendering >> " + vegetableArray.toString() );
        return vegetableArray.length;
    }

    const memoVegetableLength = useMemo(() => {
        // vegetableArray 의 값이 변경될 때만 실행됨
        console.log( "memo hooks >> " + vegetableArray.toString() );
        return vegetableArray.length;
    }, [vegetableArray])


    return (
        <>
            <p>{ fruitArray }</p>
            <button onClick={changeFruits}>changeFruit</button>
            <p>{ vegetableArray }</p>
            <button onClick={changeVegetables}>changeVegetable</button>
            <p>채소의 갯수 : {getVegetableLength()}</p>
            <p>채소의 갯수 : {memoVegetableLength}</p>
        </>
    )

}

export default UseMemoHooks;

 

위의 예제 소스코드를 보면,

changeFruit 버튼 클릭 시 fruiteArray의 값이 바뀌게 되면서 리액트는 컴포넌트를 재 렌더링을 하게 되고

이 시점에서 getVegetableLength 함수는 채소의 갯수를 구하는 함수를 재 실행하게 된다.

하지만 채소의 갯수가 변경되지 않는 시점에서 채소의 갯수를 다시 구하고 있기 때문에 이는 불필요한 함수 실행으로 볼 수 있다.

 

그렇기 때문에 memoVegetableLength 함수에 useMemo 훅을 사용하여 vegetableArray 의 값이 바뀔 때에만 채소의 개수를 세는 함수를 실행하고 채소의 개수가 바뀌지 않은 경우엔 메모이제이션에 저장되었던 채소의 갯수 값을 반환하도록 하여야 불필요한 함수 실행을 방지 할 수 있다.

 

한 편 useMemo 훅은 메모리 공간이 필요한 훅이기 때문에 불필요한 남용 또한 지양해야한다.

 


4) useCallback

: useCallback은 의존성 배열의 값이 변경될 때에 작동한다는 점에서 useMemo와 거의 유사하다.

하지만 useMemo는 값을 재사용할 수 있고 useCallback은 함수를 재사용 할 수 있다는 점에서 차이가 있다.

 

아래의 코드는 useCallback의 기본 사용법이다.

const memoizedValue = useCallback(
() => {
	handleChange(); // 함수
}, [의존성배열] )

useCallback 훅을 사용하지 않는다면 컴포넌트가 재 렌더링 될 때마다 새로운 함수들이 지속적으로 생성되게 된다. 

예를들어, 부모 컴포넌트에서 자식 컴포넌트의 props로 함수를 전달하고자 할 때 부모 컴포넌트가 재렌더링 되면 함수도 새롭게 생성되고 이로써 자식 컴포넌트까지도 다시 렌더링 되는 상황이 발생한다.

 

이런 경우 불필요한 함수 재정의를 막기 위해 useCallback 훅을 사용하여 의존성 배열의 값이 변경될 때에만 해당 함수가 다시 정의 되도록 설정해두면 부모 컴포넌트가 재 렌더링 될 때마다 [ 부모 컴포넌트 렌더링 -> 함수 새로 생성 -> 자식 컴포넌트 재정의 ] 되는 상황을 방지 할 수 있다.

'FrontEnd > React.js' 카테고리의 다른 글

[React] 리액트 훅(hooks) / useRef  (0) 2023.07.20
[React] 리액트 훅(hooks) / useState / useEffect  (0) 2023.07.18

댓글