React useCallback Hook 알아보기

지난 번에는 useMemo Hook 을 사용하여 컴포넌트를 최적화 하였습니다.

이번에는 useCallback Hook을 사용하여 조금 더 최적화를 해보겠습니다.

지난 포스팅을 보기 위해서는 아래 버튼을 클릭해주세요.

예시 코드

				
					import { useState, useMemo } from "react";

const getAverage = (numbers) => {
  console.log("Calcuating Average...");
  if (numbers.length === 0) return 0;
  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("");
  };

  const avg = useMemo(() => getAverage(list), [list]);

  return (
    <div>
      <input value={number} onChange={onChange} />
      <button onClick={onInsert}> 리스트에 추가</button>

      <ul>
        {list.map((value, index) => {
          return <li key={index}>{value}</li>;
        })}
      </ul>

      <div>
        <b>평균값 :</b> {avg}
      </div>
    </div>
  );
};

export default Average;

				
			

위 코드는 아직 useCallback 훅을 사용하기 이전의 코드입니다.

getAverage 를 불러오는 부분에 있어서 list 에 변화가 있을 때에만 불러오도록, useMemo 을 사용한 코드입니다.

다만,  Average 내부에 적용이 되어 있는 onChnage 와 onInsert 함수 또한 다시 랜더링이 되는 문제가 있습니다.

만약 하나의 컴포넌트 내부에 여러 함수를 사용한다면 이런 부분을 줄여아 할 것입니다.

useCallback 사용한 코드

				
					import { useState, useMemo, useCallback } from "react";

const getAverage = (numbers) => {
  console.log("Calcuating Average...");
  if (numbers.length === 0) return 0;
  const sum = numbers.reduce((a, b) => a + b);
  return sum / numbers.length;
};

const Average = () => {
  const [list, setList] = useState([]);
  const [number, setNumber] = useState("");

  const onChange = useCallback((e) => {
    setNumber(e.target.value);
  }, []); // 컴포넌트가 처음 랜더링 될 때에만 함수 생성

  const onInsert = useCallback(() => {
    const nextList = list.concat(parseInt(number));
    setList(nextList);
    setNumber("");
  }, [list, number]); //list 및 number 가 달라질 때만 함수 생성 

  const avg = useMemo(() => getAverage(list), [list]);

  return (
    <div>
      <input value={number} onChange={onChange} />
      <button onClick={onInsert}> 리스트에 추가</button>

      <ul>
        {list.map((value, index) => {
          return <li key={index}>{value}</li>;
        })}
      </ul>

      <div>
        <b>평균값 :</b> {avg}
      </div>
    </div>
  );
};

export default Average;

				
			

위와 같이 코드를 변경 가능합니다.

onChange 의 경우는 컴포넌트가 처음 랜더링 될 때에만 함수 생성이 되도록 [] 내부에 빈 값을 넣어줍니다.

onInsert 의 경우는 list 내부에 새로운 number 을 넣고, 해당 list 를 새로운 list 로 지정하는 로직이기 때문에,

number 와 list 에 변화에 따라 함수가 생성될 수 있도록 [] 내부에 list, number 을 넣어줍니다.

마치며...

위와 같은 로직을 이용해서 조금 더 프로젝트의 최적화를 성공했습니다.

계속해서 여러 Hook 들에 관해서 살펴보겠습니다.