- useEffect
- useMemo
- useCallback
위의 hook들의 공통점은 defendency 값의 변화에 따라 hook 내부에 속한 코드들이 통제된다는 것이다. 위 세가지 hook들을 적재적소에 사용하면 리액트가 가지는 렌더링 최적화 문제를 잘 해결할 수 있을 것이란 생각이 들어 이들의 차이점에 초점을 맞추어 정리해 보고자 한다.
간략하게 위 3가지 hook에 대해 알아보면,
일단 형태는 동일하다.
기능에 대해 알아보면 다음과 같다.
위 기능들을 좀 더 자세히 알아보기 위해,
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의 값이 변할 때만 렌더링이 새롭게 된다.