본문 바로가기
coding/front-end

[React]useCallback, Memo 함수 이해하기

by 꾸준한 개발 2022. 5. 7.
반응형

 

안녕하세요. 오늘은 React hook인  useCallback 와 memo 함수에 대해서 정리해 보겠습니다. 그전까지는 사람들이 사용하는 코드만 보고 제 프로젝트에도 적용해 봤지만 실제적으로 크게 필요한 부분에 사용하고 있지 않았습니다. 이번 기회에 확실하게 공부하고 가겠습니다!

 

 

예제 코드


App.tsx

import React, { useCallback, useState } from 'react';
import './App.css';
import Input from './components/Input';
import Btn from './components/Btn';

function App() {
  const [input, setInput] = useState<string>('');

  const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const {value} = e.target;
    setInput((prev: string) => {
      return value;
    })
  }

  const onClick = () => {
    setInput('');
  };

  return (
    <div className="App">
      <div>{input}</div>
      <Input onChange={onChange} value={input} />
      <Btn onClick={onClick}/>
    </div>
  );
}

export default App;

 

 

Input.tsx

export default function Input(props: any) {
    console.log('input');
    return (
        <input value={props.value} onChange={props.onChange} />
    )
}

 

Btn.tsx

export default function Btn(props: any) {
    console.log('button');
    return (
        <button onClick={props.onClick}>reset</button>
    )
};

 

React에서 리랜더링 되는 3가지 조건이 있습니다. 첫 번째로는 부모의 컴포넌트가 리 랜더링 되었을 때, 두 번째로는 자신의 컴포넌트 state가 변견 되었을 때, 세 번째로는 부모가 넘겨준 props의 값이 변경되었을 때입니다.

 

위에 코드를 실행하면 아래의 사진처럼 나옵니다.

 

맨 처음으로 랜더링 되었을 때 input, button 컴포넌트가 랜더링 되는 과정에서 console.log 찍은 값들이 나오게 됩니다.

 

여기서 input에 값을 입력하게 되면

input에게 넘겨준 props의 값이 변경되어서 부모 컴포넌트가 리 랜더링 되어서 btn 컴포넌트까지 리 랜더링이 되었습니다.

버튼의 값은 변경된 것이 없지만 불필요한 랜더링이 생기는 것을 방지하기 위해서 React.memo함수를 사용해서 리 랜더링을 방지해보겠습니다.

 

React.memo


React.memo는 컴포넌트를 메모를 memoization 해주는데요. 리 랜더링 과정 속에서 자신의 컴포넌트가 변한 값이 없으면 랜더링을 방지해줍니다.

 

Btn.tsx

import { memo } from "react";

export default memo(function Btn(props: any) {
    console.log('button');
    return (
        <button onClick={props.onClick}>reset</button>
    )
})

이렇게 바꿔놓고 코드를 실행해 보겠습니다.

 

하지만...

결과는 똑같았습니다. 왜 그럴까요?

 

Btn에서 props로 onClick함수를 받았습니다. 부모 컴포넌트에서 리 랜더링과정에서 onclick을 다시 생성하면서 같은 함수 이지만 다른 주소값을 가지고 있어서 다른 함수로 인식해서 리랜더링되었던 것입니다.

 

여기서 useCallback hook을 사용해서 부모가 리랜더링 되었을 때 onclick함수를 그대로 기억해서 리 랜더링을 방지해 보겠습니다.

 

UseCallback


useCallback은 함수를 재사용할 수 있도록 해주는 react hook입니다. 위 예제를 보면 input의 값이 변경되는 과정에서 부모 컴포넌트인 app 컴포넌트가 리 랜더링 되었고 그 과정에서 onclick함수도 다시 생성되어서 memo가 제대로 사용되지 못했습니다.

 

import React, { useCallback, useState } from 'react';
import './App.css';
import Input from './components/Input';
import Btn from './components/Btn';

function App() {
  const [input, setInput] = useState<string>('');

  const onChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    const {value} = e.target;
    setInput((prev: string) => {
      return value;
    })
  }, [])

  const onClick = useCallback(() => {
    setInput('');
  }, []);

  return (
    <div className="App">
      <div>{input}</div>
      <Input onChange={onChange} value={input} />
      <Btn onClick={onClick}/>
    </div>
  );
}

export default App;

위와 같이  useCallback를 사용해 주었습니다. 

 

결과는...

변경된 input만 리 랜더링이 되었고, Btn 컴포넌트는 리랜더링이 안 일어난 것을 알 수 있습니다.

 

반응형

댓글