[React] useRef 알아보기

상현·2023년 11월 7일
2

React

목록 보기
5/24
post-thumbnail

useRef

useRef hook은 크게 2가지 용도로 사용한다.
  1. DOM Selector로 사용할 때
  2. 컴포넌트를 리렌더링 하지 않고 값을 변경할 때

사용법


import { useRef } from 'react';

function MyComponent() {
  const intervalRef = useRef(0);
  const inputRef = useRef(null);
}

useRef의 인수로는 초깃값을 넣어준다. useRefcurrent라는 단일 프로퍼티를 갖는 객체를 반환하는데, 이 current에 초깃값이 들어간다

값으로 사용

useRef는 값을 갖는 current 속성을 반환하고, current는 값을 읽고, 쓸 수 있다. 값을 저장하고 다시 변경할 수 있다는 점에서 state와 비슷해 보이지만. 중요한 차이점이 있다.
state가 변경 되면 해당 state가 포함된 컴포넌트를 리렌더링하지만, ref는 변경되어도 컴포넌트가 리렌더링 되지 않는다.

따라서 useRef는 정보를 저장하고, 나중에 쓰게 될 시각적으로는 표현되지 않는 값을 설정하는데 쓰면 유리하다. 예를 들어, setInterval의 id등을 저장하는 경우이다.

function handleStartClick() {
  const intervalId = setInterval(() => {
    // ...
  }, 1000);
  intervalRef.current = intervalId;
}

❓ 그럼 일반 변수랑 뭐가 다른데 ❓

값을 저장하고, 나중에 쓰는건 일반 변수가 하는 역할과 똑같다.

// 똑같은거 아닌가??
let ref = useRef(0);
let a = 0;

a = 1;
ref.current = 1;

하지만 역시 중요한 차이점이 있다.
컴포넌트가 리렌더링 될 경우, 변수는 값이 초기화 되지만, useRef는 값을 계속 유지하고 있다.

다음 코드를 보자.

const ref = useRef(1);
let a = 1;

useEffect(() => {
  // 컴포넌트가 리렌더링 될 때마다 실행!
  console.log("ref:", ref);
  console.log("a:", a);
});

const handleChange = () => {
  a = 2;
  ref.current = 2;
  
  // state를 변경시켜 컴포넌트를 리렌더링 시킨다.
  setState(Math.random());
};

예상 되는 결과로는 handleChange 함수에서 값을 변경했어도, 컴포넌트가 리렌더링 되면서 함수를 다시 호출하기 때문에 각각 다시 1로 초기화 될 것처럼 보인다.

하지만 결과처럼 리렌더링 되면 일반 변수 a는 다시 초기화 되지만, ref는 이전의 값을 계속 가지고 있다.

재생성 피하기

const student = useRef(new Student());

useRef가 이전 값을 가지고 있어도, 컴포넌트가 리렌더링 될 때마다 new Student()를 호출하긴 한다.

따라서 이 생성자 함수가 큰 작업일 경우 쓰지도 않을 것을 매번 호출하는 건 너무 낭비일 수 있다.

다음과 같이 회피할 수 있다.

function School() {
  const student = useRef(null);
  if (student.current === null) {
    student.current = new Student();
  }
}

⚠️ 주의할 점

컴포넌트가 렌더링 중에는 ref의 값을 읽거나 쓰지 마라!

모든 리액트 컴포넌트는 순수 함수처럼 동작하기를 원한다. 즉, 입력 값이 같으면 출력 값도 같아야 한다.

하지만 중간에 ref를 읽거나 쓰는 것은 이러한 기대를 깨버릴 수 있다.

function MyComponent() {
  // ...
  // 🚩 렌더링 중에 ref의 값을 변경하지 마시오!!
  myRef.current = 123;
  // ...
  // 🚩 렌더링 중에 ref의 읽지도 마시오!!
  return <h1>{myOtherRef.current}</h1>;
}
useEffect(() => {
  // 컴포넌트가 렌더링이 전부 끝나고 바꾸거나,
  myRef.current = 123;
});

const handleChange = () => {
  // 변화 하는 이벤트를 handler에게 위임해라
  ref.current = 2;
};

return <button onClick={handleChange}>change</button>

DOM 조작으로 사용

useRef로 생성한 객체를 HTML요소에 ref속성으로 주면, 객체가 요소와 매핑된다.

ref.current에는 HTMLElement 요소가 들어가게 된다.

const inputRef = useRef();

return (
	<div>
		<input ref={inputRef} />
		<button onClick={() => inputRef.current.focus()} />
	</div>
)

참조
useRef – React

profile
프론트엔드 개발자

0개의 댓글