프론트 앤드(Front-End)/React

[React Hook] useMemo와 useCallback 개념 및 사용법

RyanSin 2021. 6. 16. 14:15
반응형

- 개요

안녕하세요. 이번 시간에는 React에서 사용되는 useMemo와 useCallback에 대해 알아보겠습니다.

 

React Hook에 대해 모르시는 분들은 아래 링크를 통해 학습하고 오시는 걸 추천드리겠습니다. (:

 

[React Hook] 함수형 Component 선언 및 useState 사용법

 

[React Hook] 함수형 Component 선언 및 useState 사용법

- 개요 안녕하세요. 이번 시간에는 React 16.8 버전부터 새롭게 추가된 Hook에 대해 알아보겠습니다. React Hook이 나오기 전까지는 Class 방식을 사용했습니다. State, Life Cycle 등등 Function Component 에는..

any-ting.tistory.com

- 개념

우리는 React로 웹 개발을 할 때 가장 중요한 개념 중 하나는 Component입니다.

 

React는 Component를 통해 View를 모듈화하고 재 사용성을 높이면서 코드의 가독성을 높여줍니다. (참 좋은 기술이에요. ^^)

 

하지만 React Component에 내부적인 구조가 어떤 식으로 구성되고 작동되는지 모른다면... 엄청 난해 한 상황이 발생합니다.

 

우리가 꼭 기억해야 할 개념들이 있습니다.

 

1. 함수형 Component는 jsx를 반환한다.

2. Component가 렌더링 된다는 것은 해당 Component를 호출했다는 것, 그렇다면 기본적으로 선언된 변수나 함수는 초기화된다.

3. Component에서 State 값이 변경되면, 해당 Component(부모)와 하위 Component(자식)는 재 렌더링 된다.

 

React에서는 이러한 구조들을 통해 작동하기 때문에 우리는 한 번만 선언해서 메모리를 유지해야 하는 상황이 발생하면, 데이터 유지가 안 되는 상황이 발생합니다.(계속... 초기화가 되는 상황 발생...)

 

이 부분을 해결하기 위해 React는 useMemo와 useCallback을 지원합니다.

 

- 사용법

*useMemo

공식 홈페이지 자료에 따른 면 useMemo는 메모 이제이 션 된 값을 반환이라고 설명하고 있습니다.

Component는 State 값이 변경될 때마다 재 렌더링 된다고 말했습니다.

 

값이 변경이 되지 않았는데, 값을 재 설정하는 것은 불 필요하겠죠?

또한, 많은 연산이 통해 값을 사용한다면 우리는  매번 많은 연산을 통해 값을 재 할당할 필요가 없겠죠:) (값이 변경되지 않았다는 조건)

 

그럼 useMemo를 사용해서 이를 해결하는 예시를 만들어 보겠습니다

- 기본 사용법

공식 홈페이지에서 사용하는 예시는 위와 같습니다.

 

useMemo 안에 첫 번째 인자는 내가 연산할 함수, 그리고 연산할 값을 배열로 지정합니다.

- useMemo 적용 X

부모 컴포넌트(App)

import react, { useState, useMemo, useCallback } from "react";
import "./styles.css";

export default function App() {
  console.log("부모!");

  const [name, setName] = useState("");
  const [age, setAge] = useState("");

  //기존 유저 이름 변경 함수
  const onChangeName = (e) => {
    const data = e.target.value;
    console.log("data : ", data);

    setName(data);
  };

  //기존 유저 이름 변경 함수
  const onChangeAge = (e) => {
    const age = e.target.value;
    console.log("age : ", age);

    setAge(age);
  };

  return (
    <div className="App">
      <h1>부모 컴포넌트</h1>

      <User
        name={name}
        age={age}
        onChangeName={onChangeName}
        onChangeAge={onChangeAge}
      />
    </div>
  );
}

자식 컴포넌트(User)

import react from "react";

const setNameTag = (name) => {
  console.log("이름 태그");

  return `이름은 : ${name}`;
};

const setAgeTag = (name) => {
  console.log("나이 태그");

  return `나이는 : ${name}`;
};

const User = (props) => {
  console.log("자식");

  //일반적인 props 받은 값
  const naem = setNameTag(props.name);
  const age = setAgeTag(props.age);

  return (
    <div>
      <h1>{naem}</h1>
      <h1>{age}</h1>
      <div>
        <input type="text" onChange={(e) => props.onChangeName(e)} />
      </div>

      <div>
        <input type="text" onChange={(e) => props.onChangeAge(e)} />
      </div>
    </div>
  );
};

실행 결과

결과를 화면을 보면 state 값이 변경되면, 부모와 자식 Component 모두 재 렌더링 되는 걸 알 수 있습니다.

그렇기 때문에 useMemo를 사용하지 않으면 설정한 값이  모두  실행되는 걸 알 수 있습니다.

- useMemo 적용 O

부모에게 받은 props를 설정하면 됩니다.

import react, { useMemo } from "react";

const User = (props) => {
  console.log("자식");

  // //일반적인 방식
  // const naem = setNameTag(props.name);
  // const age = setAgeTag(props.age);

  //useMemo 적용
  const naem = useMemo(() => setNameTag(props.name), [props.name]);
  const age = useMemo(() => setAgeTag(props.age), [props.age]);

  return (
    <div>
      <h1>{naem}</h1>
      <h1>{age}</h1>
      <div>
        <input type="text" onChange={(e) => props.onChangeName(e)} />
      </div>

      <div>
        <input type="text" onChange={(e) => props.onChangeAge(e)} />
      </div>
    </div>
  );
};

기존 코드에서 useMemo를 적용했습니다. 실행 결과 우리가 원하는 props 값만 새롭게 연산하는 걸 알 수 있습니다.

 

*useCallback

공식 홈페이지 자료에 따르면 useCallback은 메모 이제이 션된 콜백을 반환 한다고 합니다.

 

useMemo는 메모이제이션 된 값을 반환하고 useCallback은 메모이제이션 된 콜백을 반환한다고 합니다.

 

콜백을 반환한다고?... 콜백 함수를 메모리에 올려놓고, 사용한다는 뜻입니다.

- 기본 사용법

우리가 선언한 함수를 computeExpensiveValue() 위치에 넣으면 된다.

 

부모 컴포넌트 useCallback 적용

import react, { useState, useMemo, useCallback } from "react";
import "./styles.css";

export default function App() {
  console.log("부모!");

  const [name, setName] = useState("");
  const [age, setAge] = useState("");

  let count = 0;

  //기존 유저 이름 변경 함수
  const onChangeName = (e) => {
    console.log("onChangeName count 값 : ", count);

    count++;

    const data = e.target.value;
    console.log("data : ", data);

    setName(data);
  };

  //useCallback 사용
  const onChangeAge = useCallback((e) => {
    console.log("onChangeAge count 값 : ", count);
    count++;

    const age = e.target.value;
    console.log("age : ", age);

    setAge(age);
  }, []);

  return (
    <div className="App">
      <h1>부모 컴포넌트</h1>

      <User
        name={name}
        age={age}
        onChangeName={onChangeName}
        onChangeAge={onChangeAge}
      />
    </div>
  );
}

위 소스 코드를 보면 onChangeName에는 useCallback을 적용하지 않았습니다.

 

하지만 onChangeAge에는 useCallback을 적용했습니다.

 

이제 둘에 차이를 결과하면을 통해 확인해보겠습니다.

 

실행 결과 useCallback을 적용한 함수에 count 변수에 값을 +1이 되는 걸 확인할 수 있습니다.

 

이번 시간에는 useMemo와 useCallback에 대해 알아봤습니다.

 

실습을 한번 하시는 걸 추천드리겠습니다. :)