본문 바로가기

Client/React.js

<리액트 기초> useMemo & useCallback

 

* useMemo

 - 지난 장에서 보았던 컴포넌트를 이어보자.

function getWinNumbers() {
//   winNumbers라는 배열에 숫자 6개를 넣어서 반환하는 함수
}

const Test0 = () => {
  const [winNumbers, setWinNumbers] = useState(getWinNumbers());
  const [winBalls, setWinBalls] = useState([]);
  const [redo, setRedo] = useState(false);
  const timeouts = useRef([]);
  
  //...

}

 

 - 여기서 개선할 사항이 하나있다. 함수형 컴포넌트는 state의 변경에 의해서 랜더링 될때마다 컴포넌트 전체가 다시실행된다. 즉 여기서는 state가 바뀔 때마다 getWinNumbers가 계속 다시 실행된다. 만약 이 함수가 오래걸리는 함수라면 렌더링마다 그 시간이 허비된다.

 

 - 이러한 상황에서 필요한 것이 useMemo이다. useMemo는 함수의 값을 기억한다.

 

function getWinNumbers() {
//   winNumbers라는 배열에 숫자 6개를 넣어서 반환하는 함수
}

const Test0 = () => {
  const lottoNumbers = useMemo( ()=> getWinNumbers(), []);
  const [winNumbers, setWinNumbers] = useState(lottoNumbers);
  const [winBalls, setWinBalls] = useState([]);
  const [redo, setRedo] = useState(false);
  const timeouts = useRef([]);
  
  //...

}

 

 - lottoNumbers라는 임의의 변수에 useMemo를 사용하였고 함수를 담고, 두 번째 인자로 배열을 넣는다.

 

 - useEffect와 마찬가지로 두 번째 인자가 바뀌지 않는한 다시 실행되지 않는다. 위 컴포넌트의 경우에는 초기화를 하고 함수를 다시받을 버튼을 만들 것이므로 다시 실행할 필요는 없다. 따라서 빈 배열을 넣었다. 버튼또한 눌렀을 때에만 실행될 것이므로 메모리를 절약할 수 있다.

 

 - useRef와의 차이점은 useRef는 일반 값을 기억하고 useMemo는 복잡한 함수의 결과 값을 기억한다는 점이다.

 

* useCallback

 - 클릭버튼에 넣을 버튼 함수를 만들 때, 함수 컴포넌트는 전체가 계속 실행되므로 버튼 함수도 계속 새로 생성된다. 이 또한 메모리의 낭비이다.

 

 - useCallback은 함수 자체를 기억하게 하여 state의 변경에도 새로 생성되지 않도록 한다. 

 

  const onClickRedo = useCallback( () => {
    console.log(winNumbers)
    setWinNumbers(getWinNumbers);
    setWinBalls([]);
    setRedo(false);
    timeouts.current = [];
  }, [winNumbers]);
  

 

 - 함수를 useCallback으로 감싼 꼴이다. 이 때에도 두번째 인자로 배열이 있는데 역할은 위에서 봤던 것들과 동일하다. 여기서는 빈 배열을 넣어도 제대로 작동은한다. 그러나 빈배열로 작성하면 한가지 문제점이 있다. 여기서 state와 관련된 부분은 가장 처음 값만 기억하게 된다는 점이다. 만약 빈배열로 두었다면 위의 winNumbers 는 콘솔에 가장 처음 받은 배열만 계속 출력될 것이다.

 

 - 따라서 useCallback함수에서 쓰이는 state는 반드시 배열에 넣어줘야한다. 그것이 바뀌면 새로 실행되도록 해야한다. 물론 위의 경우에는 넣지 않아도 정상 작동 할 것이다.

 

 - 참고로 자식컴포넌트에 함수를 넘길때에는 useCallback이 필수이다. 만일 없다면 매번 새로운 함수가 생성되는데 자식컴포넌트에 매번 새 함수가 들어오면 매번 새로 랜더링하게 될 것이다.

 

 


 

 

참고

 

 

이 글은 ZeroCho 님의 리액트 무료 강좌를 수강하며 개인적으로 정리하며 쓰는 글입니다.

 

 

 

 

인프런

 

웹 게임을 만들며 배우는 React - 인프런

웹게임을 통해 리액트를 배워봅니다. Class, Hooks를 모두 익히며, Context API와 React Router, 웹팩, 바벨까지 추가로 배웁니다. 초급 웹 개발 프레임워크 및 라이브러리 React 웹 개발 게임개발 온라인 강

www.inflearn.com

 

유튜브

 

리액트 무료 강좌(웹게임)

 

www.youtube.com

 

 

'Client > React.js' 카테고리의 다른 글

<리액트 기초> Context API  (0) 2021.03.01
<리액트 기초> useReducer  (0) 2021.02.26
<리액트 기초> useEffect  (0) 2021.02.22
<리액트 기초> setInterval 사용하기  (0) 2021.02.19
<리액트 기초> setTimeout 사용하기  (0) 2021.02.17