useCallback 쓱 알고가기

박지성 학부생·2024년 1월 23일
1

FrontEnd Develop log

목록 보기
1/12
post-thumbnail

useCallback이란?

레이아웃짜고 오? 프론트앤드 적성인가 싶다가 갑자기 useCallback같은 문법나오면 좀 그렇다.
뭔지만 빠르게 이해하고 넘어가고 싶다면 계속 보시길

  • useCallback: 특정 함수를 다시 만들지 않고 재사용하기 위해 사용
    엥? 무슨말이지?

아직 감이 안온다면 이거 하나만 이해하면 끝 진짜로 한번만 쭉 읽어보세요

import { useEffect, useState } from "react";

//App이라는 함수형 컴포넌트 안에 
function App() {
  const [count, setCount] = useState(0);
  
// exampleFunc라는 이름의 함수가 있다. 
// 이 함수도 결국엔 exampleFunc라는 이름의 객체로 메모리에 할당된다. 
  const exampleFunc = () => {
    console.log(`함수 실행 => 카운트 성공! : ${count}`);
    return;
  };

  useEffect(() => {
    console.log("useEffect 실행");
  }, [exampleFunc]);

  return (
    <div>
      <input
        type="number"
        value={count}
        onChange={(e) => {
          setCount(parseInt(e.target.value));
        }}
      />
      <br />
      <button onClick={exampleFunc}>exampleFunc 실행</button>
    </div>
  );
}

export default App;

코드를 보면 App컴포넌트 안에 exampleFunc함수가 정의되어 있다.
여기서 중요한건 useEffect이다. 지금 useEffect의 의존성 배열은 분명 exampleFunc 함수이다.

useEffect의 의존성 배열에 exampleFunc이 있다는 것은 exampleFunc 값에 변화가 있어야 useEffect안의 내용들이 실행된다는 것이다. 근데 여기서 exampleFunc에는 실제로 함수 내용이 들어가 있는것이 아니라 console.log(함수 실행 => 카운트 성공! : ${count}); 이 코드가 저장된 주소값이 exampleFunc에 할당되어있다

// 이 코드의 탄생 경로는 App이 랜더링 될때 exampleFunc함수 안에 내용들의 주소값이 exampleFunc에 들어간다. 
// exampleFunc객체에는 사실 주소가 저장되어있다. 기능이 저장된게 아니다!! <= 이걸 이해하면 끝 이제  
const exampleFunc = () => {
    console.log(`함수 실행 => 카운트 성공! : ${count}`);
    return;
  };

위에 코드를 실행해 봤을때 처음 보이는 화면

콘솔창(처음 시작될때 당연히 exampleFunc에 주소값이 처음 할당되니까 exampleFunc값에 변화가 생긴다. => useEffect가 실행된다. )

여기서!!!!!!!!!!!! 만약 인풋에 채워져있는 count의 값 0을 다른 숫자로 바꾸면 console에 뭐라고 찍힐까?
1. 아무것도 안찍힌다.
2. "useEffect 실행"이 찍힌다.

정답은???????????


2번 useEffect 실행"이 찍힌다.

왜 count값만 바뀌고 exampleFunc이 실행되거나 값이 바뀌지 않았는데 useEffect가 실행된거지?

React 절대개념 => State가 변경되면 해당 컴포넌트는 다시 랜더링 된다.

count state가 변경이 되어 App 컴포넌트가 다시 랜더링되고 exampleFunc에 새로운 주소값이 할당됀것이다! 이에 useEffect는 오? exampleFunc에 이전과 다른 값이 들어왔네? 하고 실행된것이다.

useCallback은 이걸 막아준다!

처음만들어질때 exampleFunc에 들어간 주소값을 메모리에 박아놔서 저장한다.

// 그냥 기존 위에 코드에서 exampleFunc함수만 useCallback으로 수정했다.
import { useEffect, useState, useCallback } from "react";

function App() {
  const [count, setCount] = useState(0);

  const exampleFunc = useCallback(() => {
    console.log(`함수 실행 => 카운트 성공! : ${count}`);
    return;
  }, []);

  useEffect(() => {
    console.log("useEffect 실행");
  }, [exampleFunc]);

  return (
    <div>
      <input
        type="number"
        value={count}
        onChange={(e) => {
          setCount(parseInt(e.target.value));
        }}
      />
      <br />
      <button onClick={exampleFunc}>exampleFunc 실행</button>
    </div>
  );
}

export default App;

그냥 기존 위에 코드에서 exampleFunc함수만 useCallback으로 수정했다.
이렇게 하면 아까 질문
(1. 아무것도 안찍힌다.
2. "useEffect 실행"이 찍힌다.)
에 대한 답은 1번이 된다.

처음 시작할때만 useEffect가 실행되고 이후에 1,2,3,4를 입력하였지만 콘솔에는 아무것도 안찍힌다.
count의 상태가 변하여서 랜더링이 계속되지만 useCallback함수사용으로 console.log(함수 실행 => 카운트 성공! : ${count});의 주소가 담긴 exampleFunc객체를 메모리에 박아놔서 계속 그걸 사용한다.

따라서 exampleFunc는 쓸데없이 새로운 주소값을 할당받지 않아도 된다.

하지만 문제가 생겼다. (이제 찐막 다 끝남)


사진을 보면 처음에 0으로 시작해서 1 => 1 => 2 => 3으로 count값을 바꾸면서 버튼을 눌렀지만 계속 처음값 0으로 콘솔에 찍힌다.

원래라면 내가 바꾼 숫자로 콘솔에 찍혀야한다. 왜그럴까?

exampleFunc에 저장된 주소에는 처음 count 즉, 0으로 저장되어있기 때문

count가 변경될때마다 exampleFunc도 업데이트 해줘야한다.

방법은 그냥 useCallback의존성 배열에다가 count하나 띡 넣어주면 끝.
=> count 바뀔때마다 useCallback 업데이트해라 이런 의미

//이렇게 바꾸면 끝!
const exampleFunc = useCallback(() => {
    console.log( `함수 실행 => 카운트 성공! : ${count}`);
    return;
  }, [count]);

정리

코드만 보면 왜 굳이 useCallback을 사용하나 의문이 들 수 있지만
객체에는 주소값이 들어가고 랜더링 될때마다 필요여부를 떠나 새로운 주소값이 계속 할당되는 낭비의 개념이 잡힌다면 아 이래서 쓰는구나 알 수 있다.

profile
참 되게 살자

0개의 댓글