useRef

김민기·2022년 12월 3일
0

React

목록 보기
5/8

useRef

useRef는 크게 두 가지 경우에 사용할 수 있는 것으로 알고 있다.

컴포넌트 내부에서 변수를 사용하고 싶을 때, DOM 요소에 접근할 때

간단하게 이렇게만 알고 있었고 직접적으로 사용해 본적은 없었지만

좀 더 자세하게 알아보고 어떤 상황에서 useRef가 필요하고 어떤 방법으로 사용하는지 알아본다.

ref Object

기본적으로 useRef는 ref Object를 반환한다.

const ref = useRef("hi");
console.log(ref); // { current: "hi" }

이렇게 반환된 ref 객체는 컴포넌트의 생명주기를 함께한다. 즉 언마운트 될 때까지 값을 유지한다. 일반적으로 컴포넌트에서 변수를 사용한다면 State를 떠올릴 수 있다. State를 사용하면 컴포넌트 내부에서 변수처럼 사용할 수 있다. 하지만 State는 값이 변경될 경우 컴포넌트의 리렌더링이 발생한다. 만약 컴포넌트 에서 매우 잦은 빈도로 변경되는 값을 State로 만들었다면, 그 값이 바뀔때 마다 계속해서 렌더링이 발생하게 되고 이는 곧 성능 저하를 발생시킨다.

저장 공간으로서의 useRef

state의 변화가 발생하면 렌더링이 발생하고 이는 곧 함수형 컴포넌트의 함수가 재실행되는 것이기 때문에 내부에서 선언한 변수들이 초기화된다. 따라서 state의 변화 때문에 원치 않는 초기화가 이루어지기도 한다. 하지만 useRef를 사용한다면, ref 객체의 변화(내부의 current 값의 변화)가 발생하더라도 렌더링이 발생하지 않는다. 또한 state가 변경되어서 리렌더링 되더라도 ref 객체는 값을 유지한다.

컴포넌트가 몇번 렌더링 되었는지 카운팅 하려고 했을 때, 카운팅을 위한 변수를 만들어야 한다. 이때 state를 사용할 수 있고 useRef를 사용할 수도 있다.

import { useRef, useState } from "react";

const App = () => {
	const [count, setCount] = useState(1);
	const [renderCount, setRenderCount] = useState(1);

	// 무한 루프 발생
	useEffect(() => {
		setRenderCount(renderCount + 1);
	});

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1}>Up</butto
    </div>
  );
};

export default App;

render 횟수를 위한 renderCount 상태를 만들고 useEffect에서 렌더링 될 때마다 renderCount 상태를 변경한다. 여기서 useEffect 무한루프에 빠지게 된다. 상태가 변경되면 리렌더링이 발생하고 리렌더링useEffect를 수반한다.

이 때 useRef를 사용하면 간단하게 해결할 수 있다.

import { useRef, useState } from "react";

const App = () => {
	const [count, setCount] = useState(1);
	const renderCount = useRef(1);

	useEffect(() => {
		renderCount.current = renderCount.current + 1;
	});

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1}>Up</butto
    </div>
  );
};

export default App;

useRef로 초기값 1을 갖는 ref 객체를 renderCount에 할당한다. useEffect가 발생하여 renderCount.current 값을 수정하더라도 리렌더링은 발생하지 않기 때문에 무한루프에 빠지지 않는다.

DOM 조작

const ref = useRef();

<input ref={ref}/>

useRef가 반환하는 current 속성을 갖고 있는 ref 객체를 접근하고자 하는 요소 태그의 ref 속성으로 넣어주기만 하면 쉽게 해당 요소에 접근할 수 있다. 주로 컴포넌트가 화면에 보여졌을 때 input 태그에 포커스를 주기 위해서 사용할 수 있다.

import { useEffect, useRef } from "react";

const App = () => {
  const inputRef = useRef();

  useEffect(() => {
    console.log(inputRef);
    inputRef.current.focus();
  }, []);

  const login = () => {
    alert(`Welcom ${inputRef.current.value}`);
    inputRef.current.focus();
  };
  return (
    <div>
      <input type="text" placeholder="username" ref={inputRef} />
      <button onClick={login}>Login</button>
    </div>
  );
};

export default App;

처음 렌더링 되었을 때 useEffect에 의해서 inputRef의 current인 input HTMLElement의 함수 focus()를 실행한다. 또한 로그인 버튼을 눌렀을 때, 다시 한번 input 태그에 포커스를 줄 수 있다.

useRef를 엄청 간단히 생각하고 컴포넌트 내부에서 변수는 state를 사용하면 충분하지 않을까라는 생각을 했었다. 또한 useRef가 ref 객체를 반환하는 것도 모르고 있었다... 리액트를 잘 알고 hook들을 잘 쓰고 있다고 생각했는데 알아야 할게 너무 많은거 같다.

0개의 댓글