본문 바로가기

React/실험실

[React] useCallback의 남용

시나리오 

React Memo를 사용할 때 같이 이야기가 나오는 친구가 바로 useCallback이다 

그래서 useCallback을 사용할 때와 사용하지 않은 함수를 비교한다. 

 

머리론, useCallback이 의미없이 사용되면 일반 함수보다 시간이 더 오래 걸릴 거라는 생각이 들었다. 

 

작업 

import React, { useState } from "react";
import { useCallback } from "react";
import styled from "styled-components";

const ChildComponentOne = ({ photos }) => {
  console.log("ChildComponentOne Render");

  const handleClick1 = useCallback(() => {
    console.log("클릭");
  }, []);

  const handleClick2 = useCallback(() => {
    console.log("클릭");
  }, []);

  const handleClick3 = useCallback(() => {
    console.log("클릭");
  }, []);

  const handleClick4 = useCallback(() => {
    console.log("클릭");
  }, []);

  const handleClick5 = useCallback(() => {
    console.log("클릭");
  }, []);

  return (
    <ChildWrapper>
      {photos.map((photo) => (
        <p key={photo.id} onClick={handleClick1}>
          테스트
        </p>
      ))}
    </ChildWrapper>
  );
};

const ChildWrapper = styled.div`
  width: 45%;

  padding: 10px;
`;

export default ChildComponentOne;

ChildComponentOne의 경우 useCallback을 사용해서 의미없이 함수를 만들어봤다. 

 

import styled from "styled-components";

const ChildComponentTwo = ({ photos }) => {
  console.log("ChildComponentTwo Render");

  const handleClick1 = () => {
    console.log("클릭");
  };

  const handleClick2 = () => {
    console.log("클릭");
  };

  const handleClick3 = () => {
    console.log("클릭");
  };

  const handleClick4 = () => {
    console.log("클릭");
  };

  const handleClick5 = () => {
    console.log("클릭");
  };

  return (
    <ChildWrapper>
      {photos.map((photo) => (
        <p key={photo.id} onClick={handleClick1}>
          테스트
        </p>
      ))}
    </ChildWrapper>
  );
};

const ChildWrapper = styled.div`
  width: 45%;

  padding: 10px;
`;

export default ChildComponentTwo;

ChildComponentTwo의 경우 일반적인 함수이다. 

ChildComponentOne과 ChildComponentTwo는 비교군이다. 

 

const ParentsComponents = () => {
  const [text, setText] = useState("");
  const [photos, setPhotos] = useState([]);

  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/photos")
      .then((response) => response.json())
      .then(setPhotos);
  }, [setPhotos]);

  return (
    <div>
      <input value={text} onChange={(e) => setText(e.currentTarget.value)} />

      <Wrapper>
        <ChildComponentOne photos={photos} />
        <ChildComponentTwo photos={photos} />
      </Wrapper>
    </div>
  );
};

마지막으로 리렌더링을 발생시키기 위한 input과 각 컴포넌트를 호출시켜주는 ParentsComponent이다.

 

정리하면 

ParentsComponent에서 text라는 State를 변경시키면 

자식 컴포넌트인 ChildComponentOne과 ChildComponentTwo는 리렌더링이 발생한다. 

 

이때, useCallback이 과연 리렌더링의 성능에 영향을 주는지 확인해봤다. 

몇가지 더 예시가 있지만 결과적으로 큰 차이는 없었다. 

 

물론 더 좋은 비교 방식이 있을 수 있지만 당장 눈에 보이는 비교 방식으로는 차이를 발견하지 못했다. 

 

결과 

useCallback을 남용을 한 컴포넌트와 일반 함수를 사용한 컴포넌트를 비교했을 때,

Profiler를 사용한 렌더링 속도 차이는 비교할 수 없었다. 

 

후기 

이런 방식으로 비교하는 것이 맞는지는 모르겠다. 

하지만 지금 내가 알고있는 비교 방식으로는 차이가 없다는 결과가 나왔다. 

 

이 외에도 다양한 시도 방법이 떠오르면 다시 한번 비교를 해보겠다. 

반응형