개발자

useCallback과 useMemo를 쓰면 좋은 경우가 궁금합니다.

2023년 03월 17일조회 1,893

useCallback과 useMemo를 잘 쓰지 못하면 사용하느니만 못하다는 이야기를 들었는데, 그럼 useCallback과 useMemo 가 유용한 경우는 어떤 경우일까요?

이 질문이 도움이 되었나요?
'추천해요' 버튼을 누르면 좋은 질문이 더 많은 사람에게 노출될 수 있어요. '보충이 필요해요' 버튼을 누르면 질문자에게 질문 내용 보충을 요청하는 알림이 가요.
profile picture
익명님의 질문

답변 6

인기 답변

김하림님의 프로필 사진

설명 전에 먼저 두 가지 배경 지식을 알고 계셔야 합니다. 1. 기본적으로 React 컴포넌트는 리렌더링이되면 모든 자식들을 재귀적으로 다시 렌더링합니다. 2. React 컴포넌트 안에 정의된 함수는 렌더링마다 매 번 새로 생성됩니다. 이 배경지식을 가지고 아래의 시나리오를 읽어보시면 최적화가 어느 부분에서 필요한지를 유추해보실 수 있습니다. 1. Parent와 Child 컴포넌트가 있음 2. Parent에서 Child 컴포넌트에 handleSubmit 이라는 함수를 전달함 3. Parent 컴포넌트가 1초에 100번 렌더링됨, 이 때 handleSubmit도 100번 재생성됨 4. Child 컴포넌트는 handleSubmit이 100번 바뀌므로 Child 컴포넌트도 100번 리렌더링됨 어느 부분에서 최적화가 필요한지 감이 오시나요? 3번을 보면 handleSubmit이 100번 재생성되서 Child 컴포넌트에 불필요한 리렌더링을 유발하여 퍼포먼스 이슈를 발생시키는 것을 확인할 수 있습니다. 이 때, useCallback/useMemo를 사용하면 자식 컴포넌트의 불필요한 리렌더링을 방지할 수 있습니다. '그냥 되는대로 함수에 useCallback/useMemo를 갖다 쓰면 성능은 보장되는거 아닌가요?' 라는 악마의 유혹에 빠질수도 있습니다. 하지만 모든 것에 공짜는 없다는 사실을 기억하셔야 합니다. useCallback/useMemo는 내가 정의한 함수를 메모리에 기억하는 방식으로 최적화를 합니다. 렌더링이 여러 번 일어나도 브라우저가 이를 기억하고 있기 때문에 다시 함수를 만들지 않는 겁니다. 브라우저가 이를 기억한다는 건 무슨 의미일까요? 메모리에 함수를 저장한다는 뜻입니다. 즉, 모든 함수를 훅으로 감싼다면 브라우저의 메모리 사용량도 비례해서 커진다는 의미입니다. 따라서, 정말 필요한 경우에만 최적화를 진행하시면 됩니다.

profile picture

익명

작성자

2023년 03월 22일

좋은 답변 감사합니다! 정말 공짜는 없네요 ㅎㅎ

정주영님의 프로필 사진

정주영

링크샵스 프론트엔드 개발자1월 18일

메모리 사용량과 성능의 양쪽을 잘 고려하여 적재적소에 조심해서 써야 하겠네요. 좋은글 감사합니다.

인기 답변

영천님의 프로필 사진

하위 컴포넌트에 object를 인자로 넘겨줄때 자바스크립트 특성상 같은 object를 매번 다르다고 판단하기 때문에 ( {} === {}는 false ) 리액트에서 불필요한 렌더링을 시행하게됩니다. 이때 해당 값을 useMemo로 감싸주면 렌더링을 하지 않습니다. useCallback도 마찬가지로 함수를 하위 컴포넌트에 넘겨줄때 유용하다고 알고 있습니다

profile picture

익명

작성자

2023년 03월 22일

감사합니다 론님!

인기 답변

수민님의 프로필 사진

흥미로워 보이는 글이 있어서 추천드립니다. https://github.com/yeonjuan/dev-blog/blob/master/JavaScript/should-you-really-use-usememo.md usememo가 언제 도움이 되는지 실험한 글인데, 결론이 이렇다고 하네요! - 복잡도가 100 미만이면 useMemo가 별로 도움이 되지 않음. - 복잡도가 5000 이상인 데이터 처리가 있고 어느 정도 리렌더링이 발생한다면 useMemo가 도움이 됨. - 초기 렌더링 비용은 useMemo를 사용하면 훨씬 더 비싸지만, 후속 렌더링에서는 훨씬 성능이 향상됨.

인기 답변

이웅희님의 프로필 사진

지나가는길에 사족을 달자면 useEffect와 같은 훅의 디펜던시로 변수를 활용하기 위해서는 useCallback이나 useMemo로 해당 변수를 선언해주셔야 원하는 효과를 얻으실 수 있습니다. (변수가 primitive타입인 경우는 상관 없음)

홍지상님의 프로필 사진

현재 진행 중인 프로젝트에서 실제 용례를 말씀드려봅니다. eCharts를 사용 중이고 차트에 점을 표시합니다. fetch를 통해 새로운 데이터를 주기적으로 갱신하고, 기존과 비교해서 새로운 데이터가 있는 경우에만 리렌더링이 발생해야 하는데 컴포넌트가 마운트되고 나서부터 계속해서 리렌더링이 발생하는 버그가 있었습니다. 'useCallback'을 사용해서 데이터 의존성을 넘겨주니 문제가 해결되었습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 실제 코드에서 많이 생략했습니다.
export default function ScatterChart({ data }: ChartProps) {
  const initialChartData: ChartData[] = [];
  const chartRef = useRef(null);

  const updateChartData = useCallback(() => {
    try {
      if (!chartRef.current) return;

      const chartInstance = (chartRef.current as ReactECharts).getEchartsInstance();
      chartInstance.setOption<echarts.EChartsOption>({
        // 생략
      });
    } catch (error) {
      console.error(error);
    }
  }, [data]);

  // ... 중략 ...

  useEffect(() => {
    updateChartData();
  });

  return (
    <ReactECharts ref={chartRef} option={initialOption} opts={{ renderer: 'canvas' }} />
  );
}
kevin님의 프로필 사진

콜백과 메모를 쓰면좋은경우라기보단 근본적인 이해가 필요합니다 이것의 매커니즘은 라떼를 거슬로 올라가보면 제이쿼리나 자바스크립트 를 한창사용할시기엔 state 처럼 데이터가 변했을시 화면이 다시 렌더링이 되어야 한다! 이런개념같은것은 존재하지않았습니다 그래서 데이터변경시 필요한 화면에대해서만 그리도록 함수를 작성하는것이 대부분이였습니다 하지만 현재 리엑트의경우에는 가상돔의 하이어라키 구조가 데이터의변경에 따라서 계속 변경이되도록 되어잇죠 이말은 즉 기존에 라떼에.. 해당부분만을 다시 그리는것이아니라 모든부분이 자동으로 변경이마구되기때문에(정말로 무쟈비 하네~) 그런부분에서 리소스를 많이먹는 부분을 메모이제이션 혹은 콜백등으로 렌더링이 자주되어도 부하를 주지않도록 개선을 하는것입니다 물론 용법이나 문법 상황에대해서 말씀드릴수도있지만 이렇게 접근하는것이 좀더 이해가 쉽지않을가 생각이듭니다 모바일에서 작성해서 글이좀 보기 쉽지 않네요 ^^

지금 가입하면 모든 질문의 답변을 볼 수 있어요!

현직자들의 명쾌한 답변을 얻을 수 있어요.

또는

이미 회원이신가요?

목록으로
키워드로 질문 모아보기

실무, 커리어 고민이 있다면

새로운 질문 올리기

지금 가입하면 모든 질문의 답변을 볼 수 있어요!