221008 TIL | useMemo 알아보기

useMemo란?

  • useMemo는 연산된 값을 재사용하는 방식으로 함수 컴포넌트 내부에서 발생하는 연산을 최적화하는 Hook이다.
  • 아래와 같이 같이 사용자가 입력한 값으로 합계를 내는 함수를 작성했을 때,
  • 코드보기

      import React, { useCallback, useMemo, useRef, useState } from "react";
        
      /* eslint-disable */
      const getSum = (numbers) => {
        if (numbers.length === 0) return 0;
        console.log("값을 더하는 중..");
        return numbers.reduce((prev, current) => prev + current);
      };
        
      const Sum = () => {
        const [list, setList] = useState([0]);
        const [number, setNumber] = useState();
        const inputElem = useRef();
        
        const onChange = (e) => {
          setNumber(e.target.value);
        };
        
        const onCreate = (e) => {
          const prevList = list.concat(parseInt(number));
          setList(prevList);
          setNumber("");
          inputElem.current.focus();
        };
        
        const sumVal = getSum(list);
        
        return (
          <div>
            <input value={number || ""} onChange={onChange} ref={inputElem} />
            <button onClick={onCreate}>등록</button>
            <ul>
              {list.map((value, index) => (
                <li key={index}>{value}</li>
              ))}
            </ul>
            <div>
              <b>합계:</b> {sumVal}
            </div>
          </div>
        );
      };
        
      export default Sum;
    

Untitled

왜 값을 입력할 때마다 getSum() 함수가 호출 되나요?

  • input 컴포넌트에 change 이벤트가 발생할 때마다 컴포넌트가 리렌더링 된다.
  • 리렌더링 될 때마다 getSum() 함수가 호출되어 불필요하게 자원을 낭비하고 있다.
  • 이럴 때 useMemo 를 사용하여 성능 최적화를 할 수 있다.
    • memo는 memoized를 의미하는데 이는 이전에 계산한 값을 재사용한다는 의미를 가진다.

useMemo 사용방법

  • 첫번째 파라미터에는 어떻게 연산할 함수(getSum)를 넣어주면 된다.
  • 두번째 파라미터에는 deps 배열(list)을 넣어주면 되는데, 이 배열 안의 내용이 바뀌면 연산할 함수를 호출하고, 내용이 바뀌지 않으면 이전에 연산한 값을 재사용하게 된다.
  • useMemo 적용 코드보기

      import React, { useCallback, useMemo, useRef, useState } from "react";
        
      /* eslint-disable */
      const getSum = (numbers) => {
        if (numbers.length === 0) return 0;
        console.log("값을 더하는 중..");
        return numbers.reduce((prev, current) => prev + current);
      };
        
      const Sum = () => {
        const [list, setList] = useState([0]);
        const [number, setNumber] = useState();
        const inputElem = useRef();
        
        const onChange = (e) => {
          setNumber(e.target.value);
        };
        
        const onCreate = (e) => {
          const prevList = list.concat(parseInt(number));
          setList(prevList);
          setNumber("");
          inputElem.current.focus();
        };
        
        const sumVal = useMemo(() => getSum(list), [list]);
        
        return (
          <div>
            <input value={number || ""} onChange={onChange} ref={inputElem} />
            <button onClick={onCreate}>등록</button>
            <ul>
              {list.map((value, index) => (
                <li key={index}>{value}</li>
              ))}
            </ul>
            <div>
              <b>합계:</b> {sumVal}
            </div>
          </div>
        );
      };
        
      export default Sum;
    

    Untitled

컴포넌트가 최초 렌더링 됐을 때 1번, 함수 값을 입력한 5번만 호출이 되었다.