게시글

강좌12 - React - 한 달 전 등록 / 22일 전 수정

React Hooks! useCallback편(React 17버전)

이 포스팅들은 오래되었습니다. 유튜브에서 최신 리액트 강좌 강좌를 보시는 것을 추천합니다.

이번에는 useCallback hook에 대해 알아보도록 하겠습니다. useCallback은 함수를 캐싱(또는 메모이제이션)할 때 사용하는 훅입니다.

왜 함수를 캐싱해야하는지부터 알아야겠죠? 이전 강좌의 예제를 다시 봅시다.

import React, { useState } from 'react';
import PropTypes from 'prop-types'; // 패키지 추가 
const Basic = ({ name, birth, lang }) => {
  const [hidden, setHidden] = useState(false);
  return (
    <div>
      <span>저는 {lang} 전문 {name}입니다!</span>
      {!hidden && <span>{birth}년에 태어났습니다.</span>}
      <button onClick={() => setHidden(true)}>숨기기</button>
    </div>
  );
};
Basic.propTypes = {
  name: PropTypes.string.isRequired,
  birth: PropTypes.number.isRequired,
  lang: PropTypes.string,
};
Basic.defaultProps = {
  lang: 'Javascript',
};
export default Basic;

여기서 state가 바뀌는 경우를 가정해봅시다. state가 바뀌면 Basic 컴포넌트가 다시 실행됩니다. useState 함수도 다시 실행은 되지만 아무 효과를 주지 않는다고 했죠? 그 다음에 return 부분이 실행됩니다. 여기서 바뀌는 것은 실제로 DOM에서도 바뀌어서 반영됩니다. 이 때 조심해야 할 것이 button의 onClick 부분입니다.

() => setHidden(true)

로 되어있는데 이렇게 작성하면 Basic 함수가 다시 실행될 때마다 매번 이 함수가 새로 생성됩니다. 이것을 button의 onClick props로 넣어두었는데 함수가 새로 생성되면 props가 바뀌는 것이므로 button 태그도 리렌더링되게 됩니다. 함수 내용은 완전히 같은데 매번 다른 함수로 인식해서 리렌더링된다니 조금 당황스럽죠?

따라서 진짜 새로 생성되어야 할 상황이 아니라면 새로 생성되지 않게 막아주어야 합니다. 이 때 useCallback을 씁니다. 다음과 같이 코드를 수정합니다.

import React, { useState, useCallback } from 'react';
import PropTypes from 'prop-types'; // 패키지 추가 
const Basic = ({ name, birth, lang }) => {
  const [hidden, setHidden] = useState(false);

  const onClickButton = useCallback(() => {
    setHidden(true);
  }, []);
  return (
    <div>
      <span>저는 {lang} 전문 {name}입니다!</span>
      {!hidden && <span>{birth}년에 태어났습니다.</span>}
      <button onClick={onClickButton}>숨기기</button>
    </div>
  );
};
Basic.propTypes = {
  name: PropTypes.string.isRequired,
  birth: PropTypes.number.isRequired,
  lang: PropTypes.string,
};
Basic.defaultProps = {
  lang: 'Javascript',
};
export default Basic;

함수를 빼서 useCallback으로 감싸면 됩니다. 이러면 Basic 컴포넌트가 재실행되도 useState나 useCallback 모두 과거의 값을 가져옵니다. return 부분에서 달라지는 것이 없으므로 리렌더링이 되지 않습니다.

const onClickButton = useCallback(() => {
  setHidden(true);
}, []);

한 가지 특이한 점은 useCallback 함수의 두 번째 인수로 빈 배열이 있다는 것입니다. useCallback이 함수를 캐싱하는 것이라고 말씀드렸죠? 만약 캐싱된 함수를 다른 함수로 바꾸고 싶을 때는 어떻게 해야할까요? 이 때 빈 배열(deps 배열이라고 부릅니다)이 사용됩니다. 빈 배열에 특정한 값을 넣으면, 그 값이 변할 때만 함수를 새로 만듭니다.

예를 들어

const onClickButton = useCallback(() => {
  setHidden(true);
}, [hidden]);

위와 같이 hidden이 들어있다면 hidden값이 바뀔 때마다 내부 함수를 새로 만들어 캐싱해둡니다. 배열 안에는 하나만 넣어야 하는 것이 아니어서 여러 개의 값을 두어 그 값들이 바뀌는지 추적할 수 있습니다.

정리하자면 useCallback은 함수를 캐싱하는 hook이고, 캐싱된 것을 다시 만들고 싶다면 deps 배열을 활용하면 됩니다. return 내부에 JSX에 넣는 함수들은 거의 다 바깥으로 빼서 useCallback으로 감싸면 됩니다. 그래야 리렌더링이 최소화 됩니다.

다음 시간에는 useMemo hook을 알아보도록 하겠습니다.

조회수:
0
목록
투표로 게시글에 관해 피드백을 해주시면 게시글 수정 시 반영됩니다. 오류가 있다면 어떤 부분에 오류가 있는지도 알려주세요! 잘못된 정보가 퍼져나가지 않도록 도와주세요.
Copyright 2016- . 무단 전재 및 재배포 금지. 출처 표기 시 인용 가능.

댓글

아직 댓글이 없습니다.