React.js: useCallback();

Beautify.log·2021년 11월 4일
0
post-thumbnail

안녕하세요.

저번 포스팅에서 useMemo에 대해 살펴보았습니다. 이번 포스팅에서 알아볼 useCallbackuseMemo와 구조적으로 비슷한 Hook이라고 할 수 있습니다.

이 녀석은 렌더링 성능을 최적화 해야할 때 사용하는데, 만들어 둔 함수를 재사용할 수 있다는 특징이 있습니다.

React.js 공식 문서에서 어떻게 이야기하고 있는지 먼저 살펴볼게요.

메모이제이션된 콜백을 반환합니다.
인라인 콜백과 그것의 의존성 값의 배열을 전달하세요. useCallback은 콜백의 메모이제이션된 버전을 반환할 것입니다. 그 메모이제이션된 버전은 콜백의 의존성이 변경되었을 때에만 변경됩니다. 이것은, 불필요한 렌더링을 방지하기 위해 (예로 shouldComponentUpdate를 사용하여) 참조의 동일성에 의존적인 최적화된 자식 컴포넌트에 콜백을 전달할 때 유용합니다.
useCallback(fn, deps)useMemo(() => fn, deps)와 같습니다.

그리고 이전 포스팅에서 사용한 코드를 가져와 보겠습니다.

import React, { useState } from "react";

const getAverage = (nums) => {
  console.log("Calculating Average");
  if (nums.length === 0) return 0;
  const sum = nums.reduce((x, y) => x + y);
  return sum / nums.length;
};

const Average = () => {
  const [valueList, setValueList] = useState([]);
  const [num, setNum] = useState("");

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

  const onInsert = () => {
    const nextValueList = valueList.concat(parseInt(num));
    setValueList(nextValueList);
    setNum("");
  };
  
  const memorizedValue = useMemo(() => getAverage(valueList), [valueList]);

  return (
    <div>
      <input value={num} onChange={onChange} />
      <button onClick={onInsert}>Add</button>
      <ul>
        {valueList.map((value, index) => (
          <li key={index}>{value}</li>
        ))}
      </ul>
      <div>Average: {memorizedValue}</div>
    </div>
  );
};

export default Average;

여기에서 onChangeonInsert라는 함수를 선언해주었는데, 이런식으로 함수를 선언하게 되면 Component가 리렌더링 될 때마다 계속 새로 만들어지는 함수를 사용해야 합니다.

컴포넌트의 렌더링이 자주 발생하거나 개수가 많아지면 최적화를 해주는 것이 중요한데 이 때문에 useCallback을 사용할 수 있습니다.

onChangeonInsert를 수정해봅시다.

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

...

// 컴포넌트가 처음 렌더링될 때만 함수를 만들어줍니다.
const onChange = useCallback((e) => {
  setNumber(e.target.value);
}, []);

const onInsert = useCallback(() => {
  const nextValueList = valueList.concat(parseInt(num));
  setValueList(nextValueList);
  setNum('');
}, [num, valueList]);	// num과 valueList가 바뀔때만 함수를 만들어줍니다.

...

useCallback();의 기본꼴을 보면,

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);

이와 같이 이루어져있고, 첫번째 parameter로는 생성하고자 하는 함수를 넣고,
두번째 parameter에는 배열을 넣어줍니다.
이 때 배열은 어떤 값이 바뀌었을 때 함수를 새로 생성해야 할 지를 알려주는 것입니다.

비어 있는 배열을 넣게되면 컴포넌트가 렌더링 될 때 만든 함수를 계속적으로 사용하게 됩니다.

배열 안에 어떤 값을 넣어주게 되면 input내용이 바뀌거나 새로운 항목이 추가될 때 새로 만들어진 함수를 사용합니다.

함수 내부에서 state의 값에 의존할 때 그 값을 반드시 두번째 parameter에 표기해주어야 합니다. 왜냐하면 위의 예시에서 onInsert를 참고하면 기존의 배열을 조회해서 새로운 배열을 만들어주기 때문입니다.

profile
tried ? drinkCoffee : keepGoing;

0개의 댓글