useMemo와 useCallback & React.memo

seul_velog·2022년 4월 6일
0

React

목록 보기
6/11
post-thumbnail

1. useMemo

useMemo 는 특정 결과값을 재사용할 때 사용한다.
성능을 최적화할 때 사용한다.
Memo : "memoized" (이전에 계산 한 값을 재사용)

  • 함수연산최적화 → 어떤 함수가 있고 그 함수가 어떤 값을 리턴하고 있는데, 그 리턴까지의 연산을 최적화 하고 싶다면 사용한다. 이때 deps에 어떤 값이 변할 때만 이 연산을 다시 수행할지 명시한다.

useMemo의 파라미터

  • 첫 번째 파라미터 : 어떻게 연산할지 정의하는 함수를 넣는다.
  • 두 번째 파라미터 : deps 배열을 넣어준다.
    이 배열 안에 넣은 내용이 바뀌면 우리가 등록한 함수를 호출해서 값을 연산해준다.
    내용이 바뀌지 않았다면 이전에 연산한 값을 재사용한다.



useMemo 예제

function sum(persons) {
  console.log('sum...'); // 1)
  return persons.map((person) => person.age).reduce((l, r) => l + r, 0);
}

export default function unseMemoTest() {
  const [value, setValue] = useState('');
  const [persons] = useState([
    { name: 'Kim', age: 32 },
    { name: 'sule', age: 26 },
  ]);

  function change(e) {
    setValue(e.target.value);
  }

  const count = sum(persons); // 2)

  return (
    <div>
      <input value={value} onChange={change} />
      <p>{count}</p>
    </div>
  );
}

  • input 에 타이핑을 하게되면 unseMemoTest 함수의 렌더가 계속 실행된다. 1) 의 코드로 콘솔에 출력해보면 계속해서 출력되는 것을 알 수 있다.
  • 2) 의 count의 경우에 persons에 의존적으로 계산이 된다. 따라서 persons가 변하지 않았다면 계속해서 다시 계산될 이유가 없다.
  • 이런 경우 최적화를 위해 sum() 을 persons에 의존적으로 구해서 사용하겠다라는 의미로 useMemo 를 사용할 수 있다.

useMemo 적용하기

import React, { useMemo, useState } from 'react';

function sum(persons) {
  return persons.map((person) => person.age).reduce((l, r) => l + r, 0);
}

export default function unseMemoTest() {
  const [value, setValue] = useState('');
  const [persons] = useState([
    { name: 'Kim', age: 32 },
    { name: 'sule', age: 26 },
  ]);

  function change(e) {
    setValue(e.target.value);
  }

  const count = useMemo(() => { // 1)
    return sum(persons);
  }, [persons]); // 2)

  return (
    <div>
      <input value={value} onChange={change} />
      <p>{count}</p>
    </div>
  );
}

  • 1) useMemo 는 첫 번째 인자로 함수를 받고 함수의 결과물이 count로 할당된다.
    ❗️여기서 useMemo 만 사용하면 → 매번 useMemo 함수가 실행되어서 count에 들어간다.

  • 2) useMemo 또한 useEffet 와 같이 deps 를 두 번째 인자로 받는다. 따라서 perseon가 변했을 때만 count를 실행하도록 작성한다. → 최초의 sum 이 계산되고 이후에 input 값을 타이핑해도 콘솔창에는 뜨지 않는 걸 알 수 있다.





2. useCallback

useMemo는 특정 결과값을 재사용할 때 사용 하지만,
useCallback 은 특정 함수를 새로 만들지 않고 재사용하고 싶을 때 사용한다.

  • useCallback 은 두 번째 인자로 전달한 deps 안에 들어있는 값이 변화하지 않으면 첫번째 인자로 전달한 callback 함수를 계속 재사용할 수 있도록 도와주는 훅이다.

  • useCallback 은 내부에 들어있는 함수를 언제 새로 셋팅해 줄 것인지를 deps 에 맞춰서 (의존적으로 결정해서) 생성하고 할당한다.

  • useMemo 를 기반으로 만들어졌다. 함수를 위해서 사용할 때 더욱 편하게 해준 것이다.

  • 컴포넌트에서 props 가 바뀌지 않았다면 Virtual DOM 에 새로 렌더링 또한 하지 않는 것이 최적화 작업이라 볼 수 있다. 이와같은 최적화 작업에서는, 함수를 재사용(컴포넌트 결과물을 재사용 하는)하는 것이 필수적이다.

  • 함수 안에서 사용하는 상태 혹은 props 가 있다면 꼭 deps 배열안에 포함시켜야 한다. deps 배열 안에 함수에서 사용하는 값을 넣지 않으면 함수 내에서 해당 값들을 참조할 때 최신 값을 참조할 것이라고 보장 할 수 없다. props 로 받아온 함수가 있다면, 이 또한 deps 에 넣어주자.

function 컴포넌트는 props나 state가 변경이 되면 전체가 반복되므로 지역변수 등도 계속해서 반복되게 된다.
함수들 또한 컴포넌트가 리렌더링 될 때마다 새로 만들 어진다. 함수를 선언하는 것 자체는 메모리 등을 많이 차지하는 작업은 아니지만, 한 번 생성한 함수를 필요할 때만 새로 만들어서 재사용하는 것이 좋다.

+) ✍️ useCallback 을 했을때 기존 fecth를 통해 받아온 초기값 데이터가 적용이 안되는 이유?

: deps를 []로 줌 → 마운트 되었을때 빈 자료로 한번 불러와지고 이후부터는 해당 데이터를 참조하고있지 않도록 (useCallback) 되었기 때문에 자료는 여전히 빈 자료이다.

: deps를 변화하는 값으로 넣어줌 → useCallback 의미가 없어진다.
→ 따라서 deps를[]로 주고, setState를 설정할때 콜백함수로 이전 값을 참조할 수 있도록 작성한다.






3. React.memo

  • React.memo 함수는 컴포넌트의 props 가 바뀌지 않았다면 리렌더링을 방지해서 컴포넌트의 리렌더링 성능 최적화를 한다.

  • 즉 이 함수를 통해서 컴포넌트에서 렌더링이 필요한 상황에서만 리렌더링을 하도록 설정할 수 있다.

  • 두번째 파라미터에 propsAreEqual 이라는 함수를 사용하면 특정 값들만 비교할 수 있다.

✍️ ex.)
상위 <App/> 컴포넌트의 상태 변환으로 재렌더링이 발생할 때 자식 컴포넌트 <A/><B/> 둘다 리렌더링이된다. 이때 props로 해당되는 상태를 넘겨준 <A/> 컴포넌트 뿐만아니라 props과 관련없는 즉, 재렌더링 될 필요없는 <B/> 까지 렌더링이 발생된다.
→ 이때 업데이트 조건을 걸어서 그 조건이 변경될 때만 렌더링 하도록 한다. (물론 자신의 state가 바뀌면 리렌더링 된다.) 😀






✍️ useCallback, useMemo, React.memo 는 컴포넌트의 성능을 실제로 개선할 수 있는 상황(불필요한 렌더링을 방지할 수 있는 상황)에서만 사용하는 것이 좋다고 한다.
렌더링 최적화 하지 않을 컴포넌트에 React.memo 를 사용하는것은, 불필요한 props 비교만 하는 것이다. 🤔


✍️ useRef , useMemo , useCallback 은 이렇듯 render 사이에 어떤 상태를 유지하는 기능!

class 컴포넌트는 이런 것을 걱정할 필요가 없다. class 컴포넌트의 render 메서드만 계속 돌기 때문에 클래스 안의 여러가지 것들이 계속 유지가 된다. function 컴포넌트는 계속 function 이 생성이 되면서 그 안의 것들이 전부 새로 생성되는 경향이 있으므로 이런 부분을 낭비 하지 않도록 도와주는 기능useRef , useMemo , useCallback 이 필요한 것이다.


✍️ +) useMemo 는 함수의 연산량이 많을때 이전 결과값을 재사용하는 목적이고, useCallback 은 함수가 재생성 되는것을 방지하기 위한 목적이다.





reference)
React-Hooks
vlpt-useMemo
fastcampus-react

profile
기억보단 기록을 ✨

0개의 댓글