React/React 개념 정리

React hook! 성능 개선을 위한 useMemo

Dev dreamer 2022. 10. 22. 13:19

useMemo

useMemo를 사용하면 함수 컴포넌트 내부에서 발생하는 연산을 최적화할 수 있습니다.

 

Memo를 통해서 리랜더링의 과정의 불필요한 액션이나 메모리를 아낄 수 있습니다.

 

import { useState } from "react";

const getAverage = numbers => {
    console.log("평균값 계산 중");
    if(numbers.length === 0) return 0;
    // 배열의 각 요소를 순회하며 callback 함수의 실행 값을 누적하여 하나의 결과값을 반환 합니다.
    const sum = numbers.reduce((a, b) => a + b);
    return sum / numbers.length;
};

const Average = () => {  // 컴포넌트 이름은 대문자
    const [list, setList] = useState([]);
    const [number, setNumber] = useState('');

    const onChange = e => {
        setNumber(e.target.value);
    };

    const onInsert = e => {
        const nextList = list.concat(parseInt(number));
        setList(nextList);
        setNumber('');
    };
    return (
        <div>
            <input value={number} onChange={onChange} />
            <button onClick={onInsert}>등록</button>
            <ul>
                {list.map((value, index) => <li key={index}>{value}</li>)}
            </ul>
            <div>
                <b>평균값 : </b> {getAverage(list)}
            </div>
        </div>
    );
};
export default Average;

 

 

위의 코드를 실행시켰을때 관리자 모드에서 보면

 

평균값을 구할때 list에 기록된 값으로 평균값을 구하는 getAverage 함수만 작동하면 되는데 계속 키를 하나 입력 할 때마다 getAverage 함수가 작동이 된다. 엄청난 성능의 낭비를 가져오는 것이다.

 

이를 보완하기 위해 useMemo 훅을 사용하는데. useEffect의 의존성 배열 기능을 한번더 생각해 보면 좋을듯 싶다.

 

useEffect 는 어떠한 랜더링이 작동했을때 특정한 동작을 하도록 만든 함수인데 의존성 배열을 통해서 특정한 동작만 작동하게 하거나 처음 화면이 켜질때 작동하도록 해서 성능을 향상시켰다.

 

즉 useEffect 는 본인의 행동 범위를 설정했다면!

 

useMemo는 다른 함수가 특정한 기능에서만 혹은 특정한 변화에서만 작동하도록 세팅이 가능한 것이다.!

 

//useMemo ? 컴포넌트의 최적화를 위한 Hook(불필요한 렌더링을 막음)
import { useState, useMemo } from "react";

const getAverage = nums =>{
    console.log("평균 값 계산 중....")
    if(nums.length === 0) return 0;
    // 배열의 각 요소를 순회하면서 함수의 실행결과를 누적하여 하나의 결과값을 반환
    const sum = nums.reduce((a,b) => a+b);
    return sum / nums.length;
}

const Memo =() =>{
    const [list, setList] = useState([]);
    const [number, setNumber] =useState('');

    const onChange = e =>{
        setNumber(e.target.value);
    }
    const onInsert = e => {
        // concat 은 기존의 배열을 그대로 놔두고 새로 만드는 것.
        const nextList = list.concat(parseInt(number));
        setList(nextList);
        setNumber('');
    }
// 의존성 배열을 붙여서 list 가 바뀔때만
// 계속 반복되는 함수의 작동을 방지하고자 그 함수 대신에 useMemo로
// 의존성 함수의 기능을 추가 시켜준 값을 대신 넣어준다.
//avg 에는 두값이 들어감, 내가 호출해야하는 함수 , 의존성함수
    const avg = useMemo(() =>getAverage(list) , [list])

    return(
        <div>
            <input value = {number} onChange = {onChange} />
            <button onClick={onInsert}>등록</button>
            <ul>
                {list.map((value, index) => <li key={index}>{value}</li>)}
            </ul>
            {/* useMemo를 통해 만든 avg를 기존에 있던 getAverage(list) 대신에 넣는다. */}
                <p><b>평균값 : </b>{avg} </p>
        </div>
    );
};
export default Memo;

 

딱 봐도 위의 영상을 비교해 봤을때 관리자 창이 훨씬 편안하게 작동하고 있음을 알 수 있다.

 

변화된 코드는

 

const avg = useMemo(() =>getAverage(list) , [list])
//avg에 getAverage 함수의 기능을 부여함과 동시에 의존성 배열을 두어
//list 가 변화할 때에만 getAveraget(list)의 기능이 작동하게 했다.

//그래서 return 문 안에 들어있는 
 getAverage(list) 대신 avg를 넣어 사용한다.

<p><b>평균값 : </b>{getAverage(list)} </p>

<p><b>평균값 : </b>{avg} </p>

다음과 같이 바뀐다.

 

useEffect 를 배울때 의존성 배열로 본인의 일부 필요한 기능만 작동하게 했던것에 유용하다고 느꼈었는데

 

useMemo는 다른 함수의 기능을 딱 필요한 기능만 하게끔 설정한다는 점에서 많이 쓰이는 기능일 듯 싶다.