본문 바로가기
Frontend/React

React useCallback 개념 및 사용 방법

by Forsaken Developer 2023. 1. 31.
728x90
728x90

React useCallback 개념 및 사용 방법

useCallback

React.memo를 통해서 Button 컴포넌트가 재실행되는 것을 막고자 한다.

하지만 아래와 같이 코드를 작성하면 Button을 클릭할 때 Button컴포넌트가 재실행된다.

function App() {
  const [title, setTitle] = useState('');

  const changeTitleHandler = () => {
    setListTitle('New Title');
  }

  return (
    <div className="app">
      <Child title{title}/>
      <Button onClick={changeTitleHandler}>Change Title</Button>
    </div>
  );
}
const Button = (props) => {
  console.log('Button RUNNING');
  return (
    <button onClick={props.onClick}>
      {props.children}
    </button>
  );
};

export default React.memo(Button);

APP은 일반 함수처럼 실행되는데 이 말은 모든 코드가 다시 실행된다는 의미이다.

따라서 Button에 전달되는 이 함수는 매번 재생성되어 이 함수는 이전과 같은 함수가 아니고 같은 기능을 하는 새로운 함수이다.

props의 이전 값을 확인하고 현재의 값과 비교하는데 이 작업은 일반 비교 연산자를 통해 한다.

값이 원시값이라면 문제가 없지만 배열이나 객체, 함수를 비교한다면 말이 달라진다.

자바스크립트에서 함수는 하나의 객체에 불과하며 이 App 함수가 실행될 때마다 새로운 함수 객체가 생성이 되고 onClick props에 전달이 된다.

props.onClick과 props.previous.onClick을 비교하는데 이 두 함수 객체는 같은 내용을 갖고 있다 해도

자바스크립트에서 이 둘을 비교하면 결코 동일하지 않다.

따라서, React.memo는 자바스크립트의 이러한 작동방식 때문에 값이 변경되었다고 인식하게 되는 것이다.

useCallback 훅은 기본적으로 컴포넌트 실행 전반에 걸쳐 함수를 저장할 수 있게 하는 훅으로 리액트에게 이 함수를 저장할 것이고 매번 실행때마다 이 함수를 재 생성할 필요가 없다는걸 알릴 수 있다.

우리가 선택한 함수를 리액트의 내부 저장 공간에 저장해서 함수 객체가 실행될 때마다 이를 재사용할 수 있게 된다.

이렇게 되면, 동일한 함수 객체가 메모리의 동일한 위치에 저장되므로 이를 통해 비교 작업을 할 수 있다.

사용 방법은 저장하려는 함수를 wrapping 하면 된다.

여기에 useCallback에 저장하려는 함수를 첫 번째 인자로 전달하면 useCallback은 이 저장된 함수를 반환해준다.

useEffect와 마찬가지로, useCallback은 두 번째 인자가 필요하며 useCallback 호출에 대한 의존성 배열이다.

따라서 의존성 배열에 빈 배열을 전달하면 저장하려는 함수는 절대 변경되지 않을 것을 의미한다.

function App() {
  const [title, setTitle] = useState('');

	const changeTitleHandler = useCallback(() => {
    setListTitle('New Title');
  }, []);

  return (
    <div className="app">
      <Child title{title}/>
      <Button onClick={changeTitleHandler}>Change Title</Button>
    </div>
  );
}

의존성 배열을 지정해야 하는데 보다 보면 이게 왜 필요한지 의아할 수도 있다.

문제는 자바스크립트의 클로저이다.

자바스크립트의 함수는 클로저이고 이 말은, 함수가 정의가 되면 자바스크립트는 이 안에서 사용되는 함수 외부에서 사용하는 모든 변수를 잠그게 된다.

우리는 useCallback을 사용하여 함수를 메모리 어딘가에 저장하고 그때 함수 생성 시점의 변수의 값을 저장하고 있기 때문에 이로부터 문제가 발생하게 된다.

useCallback의 의존성에 빈배열을 전달하면 리액트에게 어떤 환경에서든 함수 재생성을 하지 않도록 전달하고 이 함수에 사용하기 위해 저장한 변수의 값도 최신의 값이 아닌 처음 실행된 시점의 값을 저장하고 있다.

의존성 배열에 변수를 전달하여 변수의 값이 바뀌면 함수를 재생성하고 항상 최신의 변수 값만 사용하고 변수가 변경되지않는다면 함수를 재생성하지않는다.

728x90
반응형

댓글