본문 바로가기

NewLearn/React

[React] useCallback()

/* 정보 전달 목적의 글 보다는 공부하면서 기억하기 위해 적는 글입니다.
따라서 깊이가 얕으며, 잘못된 정보가 있을 수 있습니다. */

useCallback

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);

 

첫 번째 파라미터 : 생성하고 싶은 함수

두 번째 파라미터 : deps 배열 (해당 배열의 어떤 값이 바뀌었을 때 함수를 생성해야하는지를 명시함.)

비어있는 배열을 넣을 경우, 컴포넌트가 렌더링될 때 만들었던 함수를 계속해서 재사용한다.

즉, 컴포넌트가 처음 렌더링될 때만 함수를 생성한다.

 

하지만 내용이 있는 배열을 넣을 경우, 해당 배열이 바뀌었을 때만 함수를 생성한다.

따라서 함수 내부에서 상태 값에 의존해야하는 경우에는 두 번째 파라미터 안에 포함시켜 줘야한다.

 

useMemo와 상당히 비슷한 함수로, 이 역시 렌더링 성능을 최적화하기 위해 사용한다.

useMemo와 비교를 하자면, 다음과 같다.

 

useCallback(fn, deps)useMemo(() => fn, deps) 와 같습니다
useMemo 는 특정 결과값을 재사용 할 때 사용하는 반면, 
useCallback 은 특정 함수를 새로 만들지 않고 재사용하고 싶을때 사용합니다.

useCallback

import React, { useState, useCallback, useMemo } from "react";

const getAverage = numbers => {
  if (numbers.length === 0) return 0;
  const sum = numbers.reduce((a, b) => a + b);
  return sum / numbers.length;
}

const MyComponent = () => {
  const [number, setNumber] = useState();
  const [list, setList] = useState([]);

  const onChange = useCallback(e => {
    setNumber(e.target.value)
  }, []);

  const onClick = useCallback(() => {
    const newList = list.concat(parseInt(number))
    setList(newList);
    setNumber();
  }, [number, list]);

  const avg = useMemo(() => getAverage(list), [list]);

  return (
    <div>
      <input name="number" value={number} onChange={onChange}></input>
      <button onClick={onClick}></button>
      <h2>{avg}</h2>
    </div>
  )
}

export default MyComponent;

 

useCallback의 느낌

import React, { useState } from 'react'
import './TodoInsert.scss'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faPlus } from '@fortawesome/free-solid-svg-icons'

const TodoInsert = () => {
  const [value, setValue] = useState('');

  const onChange = (e) => {
    setValue(e.target.value);
  }

  return (
    <form className="TodoInsert">
      <input value={value} onChange={onChange} placeholder="할 일을 입력하세요."></input>
      <button type="submit">
        <FontAwesomeIcon icon={faPlus} />
      </button>
    </form>
  )
}

export default TodoInsert;

 

위와 같이 코드를 작성하면, input의 값이 변할 때 마다(==리렌더링을 할 때 마다) onChage 함수가 새로 만들어진다. 

따라서 렌더링이 자주 발생하거나, 렌더링해야하는 컴포넌트의 개수가 많아지면 최적화를 해줘야한다.

 

 

import React, { useCallback, useState } from 'react'
import './TodoInsert.scss'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faPlus } from '@fortawesome/free-solid-svg-icons'

const TodoInsert = () => {
  const [value, setValue] = useState('');

  const onChange = useCallback(e => {
    setValue(e.target.value);
  }, []);

  return (
    <form className="TodoInsert">
      <input value={value} onChange={onChange} placeholder="할 일을 입력하세요."></input>
      <button type="submit">
        <FontAwesomeIcon icon={faPlus} />
      </button>
    </form>
  )
}

export default TodoInsert;

 

반면에 useCallback을 쓰면, 처음에 만들었던 함수를 계속해서 가져다 쓴다.

 

 

결론

useCallback 역시 값이 변경되었을 때 원하는 함수를 수행하도록 하는 함수다.

useMemo와 비교를 해보자면, useMemo는 특정 결과값을 메모이제이션하는 것이고useCallback은 함수를 메모이제이션하는 것인 것 같다. 

 

사실 아직 이해가 잘 안돼서 내일 회의 때 물어볼 예정이다.

 

 


'NewLearn > React' 카테고리의 다른 글

프로젝트 초기 셋팅하기 (CRA와 Backend 분리하기)  (0) 2021.12.20
[React] useMemo()  (0) 2021.05.04
[React] useReducer()*  (0) 2021.05.03
[React] useEffect() *  (0) 2021.05.03
[React] map, filter를 이용한 예제  (0) 2021.05.03