Tech Blog of Pinomaker
Published 2022. 8. 26. 11:38
[React] useCallback 사용하기. F.E/React
해당 자료로 공부하고 정리한 게시글 입니다.
https://www.daleseo.com/react-hooks-use-callback/

useCallback

useCallback은 useMemo와 더불어, 성능의 최적화를 위해서 사용하는 React Hook으로, useMemo가 값을 memoization 하기 위한 훅이였다면, useCallback은 함수를 memoization하기 위한 훅이다.

 

useCallback은 2개의 인자를 받는 데, 첫번째 인자는 콜백 함수, 두번째 인자는 의존성 배열을 받게 되며, 첫번째 인자로 넘어온 함수를 의존성 배열 내의 값이 업데이트 될 때까지 저장해두고 사용할 수 있다.

 

예를 들dj add() 함수는 a와 b를 받아 더한 후 반환하는 함수이고, 컴포넌트 함수 안에서 선언이 되어있기에, 해당 컴포넌트가 렌더링이 될 때 마다 새로운 함수가 생성되는 것이다.

const add = (a, b) => {
  return a + b
}

 

하지만 useCallback을 사용하면, 컴포넌트가 렌더링이 되더라도, 함수가 의존하고 있는 값들이 업데이트가 되지 않는 이상, 기존 함수를 계속 해서 반환하게 된다.

즉 a와 b가 변하게 되면, add 함수가 새로 생성되는 것이다.

const add = useCallback(() => a + b), [a, b])

 

 

하지만 컴포넌트가 렌더링 될 때 마다 함수를 새로 선언하게 되는 것은 JavaScript가 브라우저에서 얼마나 빠르게 실행되는 것을 생각해보면 성능에 있어서 큰 문제가 없다. 오히려 컴포넌트 내에서 useCallback을 함수를 반복해서 생성하지 않게 하기 위해 사용 하는 것은 의미가 없거나 손해인 경우도 있다.

 

JavaScript에서의 함수는 참조형 객체이기에, 같은 코드라고 하더라도, 같은 함수라고 하더라도, 메모리 주소에 따른 참조 비교가 일어나서 같지 않다고 나온다.

const add1 = () => a + b
const add2 = () => a + b
console.log(add1 === add2) //false

 

이러한 특성 때문에 아래의 코드에서 문제가 발생한다.

getUser 함수는 해당 함수가 변경 될 때 마다 실행이 되는 데, 문제는 함수이기에, 컴포넌트가 렌더링 될 때 마다 새로운 함수로 선언이 되어 참조값이 변경 되고, 이는 다시 useEffect가 실행되어 user의 상태 값이 바뀌고, 그러면 다시 재렌더링이 되는 무한 악숙환이 반복이 된다.

import React, { useState, useEffect } from "react"

function Profile({ userId }) {
  const [user, setUser] = useState(null)

  const getUser = () =>
    fetch("URL")
      .then((res) => res.json())
      .then(({ user }) => user)

  useEffect(() => {
    getUser().then((user) => setUser(user))
  }, [getUser])
}

 

이러한 문제를 해결하기 위해서 useCallback()을 사용하는 데, 사용하면, 컴포넌트가 렌더링 되어도 getUser는 참조값을 동일하게 유지하기에 useEffect가 다시 실행되지 않는다.

import React, { useState, useEffect } from "react"

function Profile({ userId }) {
  const [user, setUser] = useState(null)

  const getUser = useCallback(
    () =>
      fetch("URL")
        .then((res) => res.json())
        .then(({ user }) => user),
    [userId]
  )

  useEffect(() => {
    getUser().then((user) => setUser(user))
  }, [getUser])
}
profile

Tech Blog of Pinomaker

@pinomaker

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!