먼저 ref가 무엇인지 알아보자
공식문서에서는
“ref” 객체는 현재 프로퍼티가 변경할 수 있고 어떤 값이든 보유할 수 있는 일반 컨테이너입니다. 이는 class의 인스턴스 프로퍼티와 유사합니다.
Ref를 사용해야 할 때 Ref의 바람직한 사용 사례는 다음과 같습니다.
포커스, 텍스트 선택영역, 혹은 미디어의 재생을 관리할 때.
애니메이션을 직접적으로 실행시킬 때.
서드 파티 DOM 라이브러리를 React와 같이 사용할 때.
선언적으로 해결될 수 있는 문제에서는 ref 사용을 지양하세요.
라고 소개하고 있다.
저장공간
useRef는 저장공간, DOM요소에 접근을 위해 사용되는 React hooks이다. ref는 reference의 약자로
'참조'라는 뜻이다.
Ref의 가장 큰 특징은 리렌더링 하지 않는다는 것이다.
DOM 접근
또 하나의 특징은 DOM요소에 접근할 수 있다는 것이다.
하나의 sample code로 이해해보자.
input 칸에 자동 포커스를 유지하고 싶다.
import { useEffect, useRef } from 'react'
import './App.css';
function App() {
const inputRef = useRef();
useEffect(() => {
inputRef.current.focus();
}, [])
const loginAlert = () => {
alert(`환영합니다. ${inputRef.current.value}`);
inputRef.current.focus();
}
return (
<div className="App">
<header className="App-header">
<input ref={inputRef} type="text" placeholder="id"/>
<button onClick={loginAlert}>Login</button>
</header>
</div>
);
}
export default App;
login 버튼이 눌려 리렌더링 된 후에도 focus는 유지된다.
ref={inputRef} 를 통해 DOM에 접근하게 된다.
useMemo
useMemo는 의존성이 변경되었을 때에만 메모이제이션된 값만 다시 계산 할 것입니다. 이 최적화는 모든 렌더링 시의 고비용 계산을 방지하게 해 줍니다.
-공식문서-
하나의 컴포넌트가 똑같은 props를 넘겨 받았을 때 같은 결과를 렌더링 하고 있다면 React.memo를 사용하여 불필요한 컴포넌트 렌더링을 방지 할 수 있다.
React.memo를 사용할 경우 이전과 같은 props가 들어올때는 렌더링 과정을 스킵하고 가장 최근에 렌더링된 결과를 재사용 한다.
유의사항
모든 함수를 useMemo로 감싸게 되면 이 또한 리소스 낭비가 될 수 있으므로, 퍼포먼스 최적화가 필요한 연상량이 많은 곳에 사용하는 것이 좋다.
useRef와의 차이
useMemo는 deps가 변경되기 전까지 값을 기억하고, 실행후 값을 보관하는 역할로도 사용한다. 얘는 복잡한 함수의 return 값을 기억한다는 점에서 useRef와는 다르다. useRef는 특정 값을 기억하는 경우, useMemo는 복잡한 함수의 return값을 기억하는 경우에 사용한다.
useCallback 또한 리액트의 렌더링 성능을 위해서 제공되는 Hook이다.
컴포넌트가 렌더링 될 때마다 내부적으로 사용된 함수가 새롭게 생성되는 경우,
자식 컴포넌트에 Prop으로 새로 생성된 함수가 넘겨지게 되면 불필요한 리렌더링이 일어날 수 있다.
말로는 잘 이해가 되질 않을 수 있으니 code를 참고해보자
import React, {useSatate} from 'react';
import {saveToServer} from './api';
import UserEdit from './UserEdit';
function MyProfile(){
const [name, setName] = useState('');
const [age, setAge] = useState(0);
return (
<div>
<p>{`name is ${name}`}</p>
<p>{`age is ${age}`}</p>
<UserEdit
onSave={() => saveToServer(name, age)}
setName={setName}
setAge={setAge}
/>
</div>
);
}
MyProfile 컴포넌트가 렌더링 될 때마다 UserEdit 컴포넌트의 onSave 속성값으로 새로운 함수가 전달된다.
UserEdit 컴포넌트에서 React.memo를 사용해도 전달된 Prop이 항상 바뀌므로 불필요한 렌더링이 발생한다.
이 코드를 useCallback을 이용해 최적화해보면
function MyProfile(){
const [name, setName] = useState('');
const [age, setAge] = useState(0);
const onSave = useCallback(() => saveToServer(name, age), [name, age]);
return (
<div>
<p>{`name is ${name}`}</p>
<p>{`age is ${age}`}</p>
<UserEdit onSave={onSave} setName={setName} setAge={setAge} />
</div>
);
}
UserEdit 컴포넌트의 onSave 속성값으로 항상 같은 함수가 전달되어 리렌더링을 방지 할 수 있다.