반응형

🚀 useCallback()

useCallback은 useMemo와 비슷한 Hook입니다. useMemo는 특정 결괏값을 재사용할 때 사용하는 반면,  useCallback은 특정 함수를 새로 만들지 않고 재사용하고 싶을 때 사용하는 함수입니다.

 

useCallback 사용법

const memoizedCallback = useCallback(function, deps);

useCallback은 첫 번째 인자로 넘어온 함수를, 두 번째 인자로 넘어온 배열 형태의 함수 실행 조건의 값이 변경될 때까지 저장해놓고 재사용할 수 있게 해 줍니다.

예를 들어 리액트 컴포넌트 안에 함수가 선언되어있을 때 이 함수는 해당 컴포넌트가 렌더링 될 때마다 새로운 함수가 생성되는데, useCallback을 사용하면 해당 컴포넌트가 렌더링 되더라도 그 함수가 의존하는 값(deps)들이 바뀌지 않는 한 기존 함수를 재사용할 수 있습니다.

 

const add = () => x + y;

예시로 위와 같은 함수가 있다고 할 때 useCallback을 사용하면 아래와 같이 적용할 수 있습니다.

const add = useCallback(() => x + y, [x, y]);

 

useCallback 예제

useCallback은 React.memo와 함께 자식 컴포넌트의 불필요한 렌더링을 최적화할 수 있는데, 침실, 주방, 욕실의 불을 켜고 끄는 예제를 한번 살펴보겠습니다.

// App.js

import React, { useState } from "react";
import SmartHome from "./components/SmartHome";

const App = () => {
  return (
    <div style={{ position: "absolute", top: "50%", left: "50%" }}>
      <SmartHome />
    </div>
  );
};

export default App;
// ./components/Light.jsx

import React from "react";

function Light({ room, on, toggle }) {
  console.log({ room, on });
  return (
    <div>
      <button onClick={toggle}>
        {room}
        {on ? "💡" : "⬛"}
      </button>
    </div>
  );
}

export default Light;
// ./components/SmartHome.jsx

import React, { useState, useCallback } from "react";
import Light from "./Light";

function SmartHome() {
  const [masterOn, setMasterOn] = useState(false);
  const [kitchenOn, setKitchenOn] = useState(false);
  const [bathOn, setBathOn] = useState(false);

  const toggleMaster = () => {
    setMasterOn(!masterOn);
  };
  const toggleKitchen = () => {
    setKitchenOn(!kitchenOn);
  };
  const toggleBath = () => {
    setBathOn(!bathOn);
  };

  return (
    <div>
      <Light room="침실" on={masterOn} toggle={toggleMaster}></Light>
      <Light room="주방" on={kitchenOn} toggle={toggleKitchen}></Light>
      <Light room="욕실" on={bathOn} toggle={toggleBath}></Light>
    </div>
  );
}

export default SmartHome;

컴포넌트들을 생성하고 침실 토글 버튼을 클릭하고 콘솔 창을 확인해보니 침실뿐만 아니라 다른 모든 방에 대한 Light 컴포넌트 함수가 호출되는 것이 확인되었습니다.

 

조명을 켜고 끄는 방에 대해서만 Light 컴포넌트를 호출되게 하기 위해 Light 컴포넌트 부분에 React.memo를 사용해보겠습니다.

// ./components/Light.jsx

import React from "react";

function Light({ room, on, toggle }) {
  console.log({ room, on });
  return (
    <div>
      <button onClick={toggle}>
        {room}
        {on ? "💡" : "⬛"}
      </button>
    </div>
  );
}

export default React.memo(Light);

React.memo를 사용했음에도 불구하고 props가 변경되지 않았다고 생각된 침실이나 욕실 또한 컴포넌트가 렌더링 되었습니다. 그 이유는 SmartHome 컴포넌트가 렌더링 될 때마다 toggleMaster(), toggleKitchen(), toggleBath() 함수의 참조값이 바뀌어버리기 때문에 props의 변경을 감지하고 Lgith컴포넌트가 렌더링 되기 때문입니다.

따라서 해당 toggle함수들에게 useCallback 함수를 적용하면! 

// ./components/SmartHome.jsx

import React, { useState, useCallback } from "react";
import Light from "./Light";

function SmartHome() {
  const [masterOn, setMasterOn] = useState(false);
  const [kitchenOn, setKitchenOn] = useState(false);
  const [bathOn, setBathOn] = useState(false);

  const toggleMaster = useCallback(() => {
    setMasterOn(!masterOn);
  }, [masterOn]);
  const toggleKitchen = useCallback(() => {
    setKitchenOn(!kitchenOn);
  }, [kitchenOn]);
  const toggleBath = useCallback(() => {
    setBathOn(!bathOn);
  }, [bathOn]);

  return (
    <div>
      <Light room="침실" on={masterOn} toggle={toggleMaster}></Light>
      <Light room="주방" on={kitchenOn} toggle={toggleKitchen}></Light>
      <Light room="욕실" on={bathOn} toggle={toggleBath}></Light>
    </div>
  );
}

export default SmartHome;

욕실에 대한 조명을 켜보면 욕실에 대한 Light 컴포넌트만 리 렌더링 된 것을 확인할 수 있습니다.

 

 

 

 

 

📚 참고

https://www.daleseo.com/react-hooks-use-callback/

 

반응형

+ Recent posts