useEffect, useMemo, useCallback

miniminion·2022년 12월 27일
0

리액트

목록 보기
2/2
post-thumbnail
  • useEffect
  • useMemo
  • useCallback
    위의 hook들의 공통점은 defendency 값의 변화에 따라 hook 내부에 속한 코드들이 통제된다는 것이다. 위 세가지 hook들을 적재적소에 사용하면 리액트가 가지는 렌더링 최적화 문제를 잘 해결할 수 있을 것이란 생각이 들어 이들의 차이점에 초점을 맞추어 정리해 보고자 한다.

간략하게 위 3가지 hook에 대해 알아보면,
일단 형태는 동일하다.

  • useEffect(()=> func, [dependency])
  • useMemo(()=> func, [dependency])
  • useCallback(()=> func, [dependency])

기능에 대해 알아보면 다음과 같다.

  • useEffect는 dependency 배열의 값들이 바뀔 때, 내부 함수가 실행된다. dependency가 빈배열이라면 마운팅 될때만 실행된다.
  • useMemo는 내부 함수의 return 값을 저장 해 두었다가 dependency의 값이 같다면 함수를 다시 실행하지 않고 저장되어 있는 값을 return한다.
  • useCallback은 dependency의 변화가 없다면 함수를 선언하는 것을 방지한다.

위 기능들을 좀 더 자세히 알아보기 위해,
f1, f2, f3 함수가 포함된 축약된 코드를 예시로 작성해 보았다.

funtion(){
	const [state, setState] = useState(false);
    
	const f1 = () => {setState(!state); 
    				if (state===true){};}
        
    const f2 = () => {state를 사용한 시간이 오래 걸리는 계산} 
    
    const f3 = () => setState(false)
    

  return(
      <button onClick={f1}/>
      <p>{f2}</p>
      <Button onClick={f3={f3}}/> //...f3
  )
}

먼저, f1의 함수를 보면 state를 true/false로 만드는 코드 뒤에 state의 상태가 true일 때 실행되는 if문이 온다. 하지만 뒤에 오는 if문은 의도한 대로 렌더링에 반영되지 못하게 되는데, f1함수가 끝까지 실행되고 나서야 state의 변화가 반영되기 때문이다. 이럴 때 useEffect를 사용하면 해결할 수 있다.

<useEffect 사용 예시>

const f1 = () => {setState(!state)} 
useEffect(()=>{if (state===true){}},[state])    

두번째로 f2의 함수를 보면 시간이 오래 걸리는 어떤 계산을 수행하는 경우인데, 컴포넌트가 다시 렌더링 될 때마다 계속해서 수행되기 때문에 페이지 로딩 지연의 주범이 될 수 있다. 해당 함수는 state에 따라 계산을 수행하기 때문에 state가 동일하면 계산 값은 계속 같을 것이다. 이 때, useMemo를 사용해서 계산 값을 저장해 두고 렌더링마다 계산없이 값만 return한다면 페이지 로딩 시간이 보다 단축 될 것이다.

<useMemo 사용 예시>

const f2 = useMemo(()=>{state를 사용한 시간이 오래 걸리는 계산},[state])

마지막으로 f3의 경우를 보면 Button 컴포넌트에 props로 f3 함수가 전달되고 있다. 이 경우 state가 이미 false 이더라도 button이 click될 때 마다 useState가 실행되면서 렌더링이 새로 될 것이다. 그러면 useMemo를 적용하면 해결할 수 있지 않을까 생각할 수도 있지만, 이 경우에는 해결책이 되지 못한다. 왜냐하면 자식 컴포넌트가 받는 props가 함수이기 때문이다. 부모 컴포넌트에서 렌더링이 발생 시 함수가 선언될 때 마다 함수의 참조값이 바뀌면서 자식 컴포넌트에서는 계속 같은 함수를 가져오면서도 props가 바뀌었다고 인지하게 되어 useMemo 기능이 동작하지 않는다. 이 경우에 useCallback을 사용하면 된다.

const f3 = useCallback(()=>{setState(false)},[state])

기능에 대해서는 예시를 통해 알게 되었지만, 좀 더 확실하게 하기 위해 차이점에 대해 정리해보자.

먼저, 사용 목적 측면에서 [useEffect vs useMemo, useCallback] 로 나누어 생각해 볼 수 있다.

  • useEffect: 특정 상황에서 실행시키고자 할 때
  • useMemo, useCallback: 특정 상황에서 실행시키지 않고자 할 때

언뜻 비슷하게 느껴지는 것들끼리 비교해 보자

[useEffect vs useMemo]

  • useEffect: 렌더링 된 후 실행
  • useMemo: 렌더링 중 실행

[useMemo vs useCallback]

  • useMemo: 메모리에 return 값을 저장
  • useCallback: 메모리에 함수 선언을 저장(참조값이 불변)

참고)

  • defendency에 객체를 넣는 것을 지양한다. 객체는 렌더링 될 때마다 참조값이 바뀌기 때문이다.

  • 자바스크립트 데이터 타입은 크게 원시형(Primitive Type)과 참조형(Reference Type)으로 분리된다.
    -원시형 데이터: Number, String, Boolean, null, undefined, Symbol
    -참조형 데이터: Object, Array,Function,정규표현식(RegExp),Map, Set, WeakMap, WeakSet

  • react.memo를 사용하면 useMemo와 같은 결과를 얻을 수 있다. 차이점은, react.memo는 hook이 아닌 Higher-Order Components(HOC)라서 클래스형, 함수형 컴포넌트에 모두 사용가능하지만 useMemo는 hook이기 때문에 함수형 컴포넌트에만 사용 가능하다.

import React,{ memo } from "react";

function Child(props){
	...
    
	return
	}
    
export default memo(Child);

이렇게 하면 부모 컴포넌트들이 새로 불러와 지더라도 자식 컴포넌트인 Child는 props의 값이 변할 때만 렌더링이 새롭게 된다.

0개의 댓글