Posts Useref
Post
Cancel

Useref

https://react-ko.dev/reference/react/useRef

렌더링에 필요하지 않은 값을 참조할 수 있는 Hook

1
const ref = useRef(initialValue)

Caveats

  • ref.current 는 mutate 가능하다. 하지만 렌더링에 사용되는 객체(state의 일부)를 포함하는 경우 mutate해서는 안된다.
  • ref.current는 변경해도 컴포넌트가 리렌더링되지 않는다. React는 해당 값이 언제 바뀌었는지 알지 못한다.
  • 초기화를 제외하고 렌더링 중에 ref.current를 쓰거나 읽으면 안된다.
  • Strict Mode 에서는 React는 컴포넌트 함수를 두번 호출한다. useRef도 마찬가지라 ref 객체는 두 번 생성되고 하나는 버려진다.

Usage

Referencing a value with a ref

ref는 변경 시 리렌더링을 촉발하지 않는다. 따라서 UI에 영향을 미치는 정보를 저장하면 안되고, intervalId 같이 UI에 영향을 미치지 않는 값을 저장해야한다.

ref는 또한 다음을 보장한다.

  • 리렌더링 사이에 정보를 저장할 수 있다.
  • 리렌더링을 촉발하지 않는다.
  • 각각의 컴포넌트에 로컬로 저장된다.

Do not write or read ref.current during rendering

React는 컴포넌트 본문이 순수함수처럼 동작하기를 원한다. 입력값(props, state, context)가 똑같으면 똑같은 JSX가 나와야한다. 렌더링 중에 ref를 읽거나 쓰면 이러한 기대가 깨진다.

1
2
3
4
5
6
7
function MyComponent() {  
	// 🚩 렌더링 중에 ref를 작성하지 마세요.  
	myRef.current = 123;  
	
	// 🚩 렌더링 중에 ref를 읽지 마세요.  
	return <h1>{myOtherRef.current}</h1>;  
}

대신 이벤트 핸들러나 Effect에서는 읽거나 쓸 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
function MyComponent() {  
	// ...  
	useEffect(() => {  
		// ✅ Effect에서 ref를 읽거나 쓸 수 있습니다.  
		myRef.current = 123;  
	});  
	
	// ...  
	function handleClick() {  
		// ✅ 이벤트 핸들러에서 ref를 읽거나 쓸 수 있습니다.  
		doSomething(myOtherRef.current);  
	}  
}

Avoiding recreating the ref contents

ref 초기 값은 한번 저장하고 다음 렌더링부터는 무시하지만, 아래와 같은 경우 호출 자체는 매번 이루어진다.

1
2
function Video() {  
	const playerRef = useRef(new VideoPlayer());

따라서 다음과 같이 초기화인 경우에 한하여 렌더링 중에 ref.current를 읽고 쓰는 작업을 통해 낭비를 줄일 수 있다.

1
2
3
4
5
function Video() {  
	const playerRef = useRef(null);  
	if (playerRef.current === null) {  
		playerRef.current = new VideoPlayer();  
	}

이경우 결과가 항상 동일하고, 초기화 중에만 조건이 실행되므로 예상가능하여 괜찮다.

get ref to a custom component

기본적으로 컴포넌트는 내부의 DOM 노드에 대한 ref를 외부로 노출하지 않는다. 따라서 커스텀 컴포넌트에 대한 ref를 사용하려면 다음과 같이 forwardRef를 사용할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
import { forwardRef } from 'react';  

const MyInput = forwardRef(({ value, onChange }, ref) => {  
	return (  
		<input  
			value={value}  
			onChange={onChange}  
			ref={ref}  
		/>  
	);  
});
This post is licensed under CC BY 4.0 by the author.