useCallback

SebellKO·2023년 11월 29일

React

목록 보기
14/15
post-thumbnail

이전 포스팅에서 React.memo의 얕은 객체 비교를 통해 발생하는 한가지 오류에 대해서 살펴봤다.

즉, 함수를 포함한 객체는 memo함수를 이용한 메모이제이션이 적용되지 않는다.

왜 함수는 memo 함수를 통해 메모이제이션이 되지 않을까 ?

그 이유는 자바스크립트의 참조에 의한 전달과 컴포넌트의 동작과정에 있다.

첫번째로 컴포넌트는 함수이기 때문에 렌더링시 블록 내부의 선언된 함수가 다시 선언되게 된다.

그렇기 때문에 렌더링 될때마다 함수는 다른 주소값을 가지게 된다.

그리고 두번째로 자바스크립트의 참조에 의한 전달이다.
즉, 저장된 값을 전달하는것이 아닌 저장된 주소값을 전달한다.

그렇기 때문에 컴포넌트가 다시 렌더링 될때마다 내부에 선언된 함수는 각기 다른 주소값을 갖게되고 memo에의한 얕은 비교에 걸러지게 되는것이다.

이는 useCallback 함수를 사용해 해결할 수 있다.

이전 포스팅의 예제를 다시 살펴보자.

import React, { useRef, useState } from 'react';

import './App.css';

function App() {
  const content = useRef();

  const [isTitle, setIsTitle] = useState(false);
  const [title, setTitle] = useState('');
  const [subTitle, setSubTitle] = useState('');

  const switchHandler = () => {
    setIsTitle(!isTitle);
  };

  const submitHandler = (event) => {
    event.preventDefault();
    if (isTitle) setTitle(content.current.value);
    if (!isTitle) setSubTitle(content.current.value);
    content.current.value = '';
  };

  return (
    <div className="app">
      <Title title={title}></Title>
      <SubTitle subTitle={subTitle}></SubTitle>
      <Button onClick={switchHandler} text={'Switch'}></Button>
      <form onSubmit={submitHandler}>
        <input
          type="text"
          placeholder={isTitle ? 'title' : 'subtitle'}
          ref={content}
        ></input>
        <button type="submit">Submit</button>
      </form>
    </div>
  );
}

<Button/> 컴포넌트에 prop으로 전달되는 switchHandler를 메모이제이션 하려고 한다.

useCallback 메소드를 적용해 리액트에게 함수의 저장을 알려야 한다.

const switchHandler = useCallback(() => {
    setIsTitle(!isTitle);
  }, []);

useCallback을 이용해 저장하려는 함수를 감싸주고 두번째 인자로 의존성 배열을 설정한다.

위 코드는 이제 항상 같은 함수로 저장되어 사용된다.

하지만 브라우저의 성능의 증가로 인해 useCallback 함수는 확연히 눈에 보일만한 성능 최적화를 가져다 주기 어렵다.

그러니 시기 적절한 때를 잘 판단하여 사용해야 한다.

React.memo와 같이 사용해 함수를 prop으로 전달받는 컴포넌트의 재 렌더링을 방지하자.

0개의 댓글