웹개발/React.js

리액트 Ref란? State와 차이점 위주로

조맹구 2023. 11. 13. 17:42

When you want a component to “remember” some information, but you don’t want that information to trigger new renders, you can use a ref.
어떤 컴포넌트가 특정 정보를 기억하게 하고 싶지만, 새로운 렌더를 일으키고 싶지 않을 때 사용한다 (공식문서)

 

html에서 DOM 요소에 이름을 달 때는 id를 사용한다.
리액트 내부에서 DOM에 이름을 다는 방법은 바로 ref

Q. 리액트 컴포넌트 안에서 id를 사용하면 안되나요?

 

사용해도 되지만 HTML에서 DOM id는 유일해야 하는데 중복의 위험이 있다. ref는 전역적으로 작동하지 않고 컴포넌트 내부에서만 작동하기 때문에 이런 문제가 생기지 않는다.

 

Ref는 어떤 상황에 사용할까?

DOM을 꼭!! 직접 건드려야 할 때. 근데 새로운 렌더를 일으키고 싶지 않을 때 사용한다.

예를 들어

  • 특정 input에 포커스주기
  • 스크롤 박스 조작하기
  • Canvas 요소에 그림그리기
  • JSX 연산이 불필요한 오브젝트 저장

Ref가 State와 다른점

사진처럼 Ref는 리액트가 주시하고 있지 않는 컴포넌트의 비밀 포켓 같은 존재로 ref의 현재 값을 ref.current로 접근할 수 있다.

  • ref도 state처럼 무엇이든 가르킬 수 있다. (string, object, function 등등)
  • ref는 state와 달리 current property를 갖는 plain javascript object로 읽고 수정할 수 있다.
  • ref는 state와 달리 변화를 주어도 리렌더하지 않는다.
Refs State
useRef(initialValue)는 {current:initialValue}를 반환한다. useState(initialValue)는 [value,setValue]를 반환한다.
리렌더를 트리거하지 않는다 state가 변경될 때, 리렌더를 트리거한다.
렌더링 사이클 외부에서 current 값을 변경, 유지할 수 있다. state값을 변경하기 위해서는 반드시 set함수를 사용해야 한다.
렌더링 중에 current값을 읽거나 쓸 수 없다. state값을 아무때나 읽을 수 있다. 하지만 각 렌더는 state의 변경되지 않는 스냅샷을 가지고 있다.

Ref와 State 비교 코드

useState 사용 코드

import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <button onClick={handleClick}>
      You clicked {count} times //컴포넌트를 리렌더해주기 때문에 screen에 업데이트된 count가 반영됨
    </button>
  );
}

useRef 사용코드

import { useRef } from 'react';

export default function Counter() {
  let countRef = useRef(0);

  function handleClick() {
    // This doesn't re-render the component!
    countRef.current = countRef.current + 1;
    console.log(countRef.current)
  }

  return (
    <button onClick={handleClick}>
      You clicked {countRef.current} times //렌더시키지 않아서 보여지지 않음 
    </button>
  );
}

Best practices for refs

  1. Treat refs as an escape hatch
    : 외부 시스템이나 브라우저 APIs와 사용할 때 유용하다. 예를 들어 input에 포커스를 주기
  2. Don't read or write ref.current during rendering.
    : 만약 렌더링 하는 와중에 정보가 필요하다면 state를 사용하자. 렌더링하는 동안에 리액트가 언제 ref.current가 변하는지 모르기 때문에
    렌더링 동안에는 ref.current를 읽거나 쓰지 않아야 한다.
  3. Ref값은 변경 즉시 바뀐다.
참고
- 리액트 공식문서 https://react.dev/learn/referencing-values-with-refs
- 리액트 다루는 기술 (김민준 저)