useCallback

크롱·2024년 1월 3일
0

React

목록 보기
12/18

useCallback ? 콜백함수 그 자체를 메모이제이션

예제




값이 3일때 callSomeF 버튼을 누르고, 다시 input의 number을 2번 클릭해서 5로 바꿨는데, 왜

useEffect(() => {
    console.log('someF 실행가즈앙');
  }, [someF]);

이 함수가 실행됐을까? someF는 그대로인데..
왜냐면?
number의 state가 바뀌면서, App컴포넌트가 다시 렌더링되는데, 이때

const someF = () => {
  console.log(`someF:${number}`);
  return;
};

이 변수도 초기화가된다. 이 변수는 함수이므로, 참조형 데이터. 즉, 메모리주소가 저장된건데,
이 변수가 초기화될때 똑같은함수이지만 새로운 메모리공간에 저장이되므로 메모리주소가 변한다. 바뀐메모리주소가 someF에 할당이되는것.
리액트입장에서는 someF의 주소가바뀐거니 변수의값(메모리주소)이 바뀐거나 다름없는것! 그래서

useEffect(() => {
    console.log('someF 실행가즈앙');
  }, [someF]);

요게실행된다.
이를 막으려면, useCallback~

주의사항

const someF = useCallback(() => {
  console.log(`someF:${number}`);
}, []);

만약 의존성배열에 빈 배열을 넣게되면,

number가 6일때 버튼을 눌러도

콘솔에는 0이 출력된다.
처음렌더링될때, number가0일때 메모이제이션이됐기때문에!

제대로 동작하게하려면, 의존성배열에 number를 넣어주자

const someF = useCallback(() => {
  console.log(`someF:${number}`);
}, [number]);

이렇게 해주면 정상작동한다!

useEffect(() => {
    console.log('someF 실행가즈앙');
  }, [someF]);

number가 바뀌면 아까처럼 얘 또한 작동해서 콘솔로그 'someF 실행가즈앙'가 찍힌다. 왜냐면, number가바뀌면 someF가 바뀌니까

토글 추가

const [toggle, setToggle] = useState(true);

<button onClick={() => setToggle(!toggle)}>{toggle.toString()}</button>

버튼을 추가해서 useCallback 적용 전후를 비교해보자.

  • useCallback 적용 전
 const someF = () => {
    console.log(`someF:${number}`);
    return;
  };

  useEffect(() => {
    console.log('someF 실행가즈앙');
  }, [someF]);


토글버튼을 누르면, toggle의 상태가변하면서 someF가 초기화되면서 useEffect내 함수가 실행된다.

  • useCallback 적용 후
  const someF = useCallback(() => {
    console.log(`someF:${number}`);
    return;
  }, [number]);

  useEffect(() => {
    console.log('someF 실행가즈앙');
  }, [someF]);

토글버튼을 누르면, toggle의 상태가변하는데 App컴포넌트가 렌더링될때 someF는 메모이제이션으로인해 useEffect내 함수가 실행되지않는다





실전 예제

  • App.js
import Box from './Box.js';
export default function App() {
  const [size, setSizes] = useState(100);
  const [isDark, setIsDark] = useState(false);
  const BoxStyle = () => {
    return {
      backgroundColor: 'pink',
      width: `${size}px`,
      height: `${size}px`,
    };
  };
  return (
    <div
      style={{
        backgroundColor: isDark ? 'black' : 'yellow',
      }}
    >
      <input
        type="number"
        value={size}
        onChange={(e) => setSizes(e.target.value)}
      />
      <hr />
      <Box BoxStyle={BoxStyle} />
      <button onClick={() => setIsDark(!isDark)}>change</button>
    </div>
  );
}
  • Box.js
const Box = ({ BoxStyle }) => {
  const [style, setStyle] = useState({});
  useEffect(() => {
    console.log('박스 사이즈 조절~');
    setStyle(BoxStyle());
  }, [BoxStyle]);

  return <div style={style}></div>;
};

export default Box;



change를 누르면

useEffect(() => {
    console.log('박스 사이즈 조절~');
    setStyle(BoxStyle());
  }, [BoxStyle]);

이 코드가 실행이된다. isDark의 state가 변하면서 App컴포넌트가 재렌더링되면서,

const BoxStyle = () => {
    return {
      backgroundColor: 'pink',
      width: `${size}px`,
      height: `${size}px`,
    };
  };

이 BoxStyle함수가 다시 초기화되는데, 함수객체이기때문에 다른 메모리주소값이 저장되기때문! 그래서 리액트는 BoxStyle이 변했으니까, useEffect를 실행하는거다. 나는 isDark의 state를 변화시켰는데 isDark와 상관없는 함수가 실행되고있으니까 이를 막으려면 useCallback~

  const BoxStyle = useCallback(() => {
    return {
      backgroundColor: 'pink',
      width: `${size}px`,
      height: `${size}px`,
    };
  }, [size]);

이제 isDark의 state가 변화가 되어도, useEffect는 일어나지않는다.


모든 출처: 별코딩 유튜브

profile
👩‍💻안녕하세요🌞

0개의 댓글