React useCallback을 사용하는 이유

최문경·2022년 1월 19일
1

React memo를 사용하는 이유 글에서 이어집니다.

왜 Button컴포넌트만 재실행될까? 그것은 Paragraph컴포넌트의 props로는 원시 타입인 false를 넘겨줬고 Button컴포넌트의 props로는 함수를 전달해줬기 때문이다.

App컴포넌트가 재실행될 때마다 toggleParagraphHandler함수가 새로 만들어지는데 분명 함수의 내용은 같지만 자바스크립트에서의 함수는 객체이기 때문에 Button컴포넌트에서는 props가 바뀌었다고 생각해서 컴포넌트를 재실행하는 것이다.
(객체는 메모리에 저장할 때 값을 저장하는 것이 아니라 값의 주소를 저장하기 때문에 같은 값을 가진 객체일지라도 일치연산자로 비교했을 때 false가 출력됨)

이러한 상황에서 함수를 useCallback으로 감싸주면 react가 함수를 저장하고 두 번째 매개변수인 dependencies가 변경되지 않는다면 함수를 재생성하지 않기 때문에 해당 함수를 props로 가지는 자식 컴포넌트들은 함수가 바뀌었다고 생각하지 않게 된다.

따라서, 자식 컴포넌트의 props로 전달해주는 함수들은 useCallback을 사용해주면 재실행이 일어나는 횟수가 줄어들기 때문에 더 효율적인 앱을 만들 수 있을 것이다!

// App.js
import { Fragment, useState } from 'react';

import Button from './components/Button';
import Paragraph from './components/Paragraph';

function App() {
  console.log('App Running');

  const [showParagraph, setShowParagraph] = useState(false);

  const toggleParagraphHandler = useCallback(() => {
    setShowParagraph((prevState) => !prevState);
  }, []);

  return (
    <Fragment>
      <Paragraph show={false} />
      <Button onChangeText={toggleParagraphHandler} />
    </Fragment>
  );
}

export default App;
// Paragraph.js
import react from 'react';

const Paragraph = (props) => {
  console.log('Paragraph Running');

  return <p>{props.show ? 'HELLO' : ''}</p>;
};

export default react.memo(Paragraph);
// Button.js
import react from 'react';

const Button = (props) => {
  console.log('Button Running');

  return <button onClick={props.onChangeText}>Change Text!</button>;
};

export default react.memo(Button);

useCallback으로 감싸주니 이제 Button컴포넌트도 재실행되지 않는 모습을 볼 수 있다.

profile
프론트엔드 공부하고 있습니다!

0개의 댓글