useMemo(): Memoized value 를 리턴하는 Hook
Memoization
for 최적화.
비용이 높은, 연산양이 많은 함수 호출 결과를 저장해 두었다가
같은 입력 값으로 함수를 호출하면 새로 함수를 호출하지 않고
이전에 저장해 놨던 호출 결과를 바로 반환하는 것
함수 호출 결과를 받기까지의 시간도 짧아질 뿐더러, 불필요한 중복 연산x
=> 컴퓨터의 자원을 적게 쓰게됨
- Memoization이 된 결과값 = Memoized value
('Memo' = 메모하다, 메모를 해 두었다가 나중에 다시 사용하는 것)

useMemo() 훅은 파라미터로 Memoized value를 생성하는 create 함수와 의존성 배열을 받습니다.
Memoization 의 개념처럼 의존성 배열에 들어있는 변수가 변했을 경우에만 새로 create 함수를 호출하여 결과값을 반환하며, 그렇지 않을 겨우 기존 함수 결과값을 반환합니다.
빠른 렌더링 속도
useMemo() 로 전달된 함수는 렌더링이 일어나는 동안 실행된다.
그렇기 때문에 일반적으로 렌더링이 일어나는 동안 실행되서는 안될 작업을 useMemo() 함수에 넣으면 안됩니다.
예를 들면 useEffect()에서 실행되어야 할 Side effect 같은 것이 있습니다. 서버에서 데이터를 받아 오거나 수동으로 DOM을 변경하는 작업 등은 렌더링이 일어나는 동안 실행되서는 안되기 때문에 useMemo() 훅 함수에 넣으면 안되고, useEffect() 훅을 사용해야 합니다.


하지만 대부분의 경우에는 useMemo()의 의존성 배열에 변수들을 넣고 해당 변수들의 값이 바뀜에 따라 새로 값을 계산해야 할 경우에 사용합니다.
useMemo() Hook 과 유사하지만 값이 아닌 함수를 반환

만약 useCallback() 훅을 사용하지 않고 컴포넌트 내에 함수를 정의한다면 매번 렌더링이 일어날 때마다 함수가 새로 정의됩니다.
예를 들어, 이 코드처럼
import { useState } from "react";
function ParentComponent(props) {
const [count, setCount] = useState(0);
//////// 재렌더링 될 때마다 매번 함수가 새로 정의됨 ////////
const handleClick = (event) => {
// 클릭 이벤트 처리
};
///////////////////////////////////////////////////////
return (
<div>
<button
onClick={() => {
setCount(count+1);
}}
>
{count}
</button>
<ChildComponent handleClick={handleClick} />
</div>
);
}
하지만 useCallback() 훅을 사용하면
import { useState } from "react";
function ParentComponent(props) {
const [count, setCount] = useState(0);
////////// 컴포넌트가 마운트 될 때만 함수가 정의됨 //////////
const handleClick = useCallback((event) => {
// 클릭 이벤트 처리
}, []);
////////////////////////////////////////////////////////
return (
<div>
<button
onClick={() => {
setCount(count+1);
}}
>
{count}
</button>
<ChildComponent handleClick={handleClick} />
</div>
);
}
useRef(): Reference를 사용하기 위한 Hook
그렇다면 Reference란 무엇일까요?
Reference
특정 컴포넌트에 접근할 수 있는 객체
그리고 useRef() 훅은 바로 이 reference 객체를 반환합니다.
refObject.current


쉽게 말해 useRef 훅은 변경 가능한 current 라는 속성을 가진 하나의 상자라고 생각하면 됩니다.
function TextInputWithFocusButton(props) {
const inputElem = useRef(null);
const onButtonClick = () => {
//'current'는 마운트된 input element를 가리킴
inputElem.current.focus();
};
return (
<>
<input ref={inputElem} type="text" />
<button onClick={onButtonClick}>
Focus the input
</button>
</>
);
}
<input ref={inputElem} .../><button onClick={onButtonClick}.../> 호출되는 함수( onButtonClick )에서, inputElem.current 를 통해 실제 엘리먼트에 접근하여 focus() 함수를 호출하고 있습니다.이전에 웹사이트 개발을 해 본 분들은 레퍼런스와 관련하여 DOM에 접근하기 위해 사용하는 ref 속성에 익숙할 수도 있습니다.
<div ref={myRef} />
비슷하게 리액트에서는 위와 같이 코드를 작성하면 노드가 변경될 때마다
myRef의 current 속성에 현재 해당되는 DOM 노드를 저장합니다.
ref 속성과 기능은 비슷하지만 useRef 훅은 클래스의 인스턴스 필드를 사용하는 것과 유사하게 다양한 변수를 저장할 수 있다는 장점이 있습니다.
이런 것이 가능한 이유는 useRef 훅은 일반적인 자바스크립트 객체를 리턴하기 때문입니다.
라고 생각할 수도 있습니다. 물론 그렇게 해도 목적 달성은 가능할 수 있지만 요즘에 훅을 사용하는 것과 직접 current 속성이 포함된 모양의 객체를 만들어 사용하는 것의 차이점은, useRef 훅은 매번 렌더링될 때마다 항상 같은 레퍼런스 객체를 반환한다는 것입니다.
그리고 중요하게 기억해야 할 점은,
useRef() Hook은 내부의 데이터가 변경되었을 때 별도로 알리지 않는다
는 것입니다.
그래서 current 속성을 변경한다고 해서 재렌더링이 일어나지는 않습니다.
따라서 ref에 DOM 노드가 연결되거나 분리되었을 경우에 어떤 코드를 실행하고 싶다면 CallBack ref를 사용해야 합니다.
Callback ref
function MeasureExample(props) {
const [height, setHeight] = useState(0);
const measureRef = useCallback(node => {
if (node != null) {
setHeight(node.getBountingClientRect().height);
}
}, []);
return (
<>
<h1 ref={measureRef}>안녕, 리액트<h1>
<h2>위 헤더의 높이는 {Math.round(height)}px 입니다.</h2>
</>
);
}
useMemo(): Memoized value 를 리턴하는 HookuseMemo(() => 함수, 의존성 배열);-전달되는 함수는 렌더링하는 동안 실행됨
useCallback(): useMemo() Hook 과 유사하지만 값이 아닌 함수를 반환useCallback(함수, 의존성 배열);-의존성 배열에 있는 변수 중 하나라도 변경될 때만 memoization된 callback 함수를 재정의 후 반환
useRef(): Reference를 사용하기 위한 HookuseRef(초깃값);- 해당 초깃값으로 초기화된 reference 객체( 특정 컴포넌트에 접근할 수 있는 객체 )를 반환
- refObject.current : current 는 reference 객체의 속성. 현재 참조하고 있는 엘리먼트를 말함
=> useRef 훅은, "변경 가능한 current 라는 속성을 가진 하나의 상자"이다.
- current 속성을 변경한다고 해서 재렌더링이 일어나지는 않는다.
=> Callback ref 방식 : useCallback()을 이용해서 자식 컴포넌트가 변경되었을 때 알림을 받을 수 있음 ( 빈 의존성 배열[]을 넣으면 마운트/언마운트될 때만. )