[React] useRef란 ?

James·2023년 9월 6일
0

React

목록 보기
6/20
post-thumbnail
post-custom-banner

useRef 란?


  1. Dom노드나 React엘리먼트에 접근하는 것이 가능하다.

  2. 값이 변경되어도 re-render를 일으키지 않는다.

    • 같은 메모리 주소를 갖고있기 때문에 자바스크립트의 === 연산이 항상 true 를 반환합니다. 즉 변경사항을 감지할 수 없어서 리렌더링을 하지 않는다는 뜻입니다.
  3. useRef()는 일반적인 JS 객체이다.

    • 즉, heap영역에 저장되는 변수이다.

    • 실제로 useRef를 코드로 확인해보면 순수 자바스크립트 객체로 만들어진 hooks이다.

왜 useRef를 사용하는가?

  1. 불필요한 메모리 사용 줄일 수 있다.
  2. 불필요한 리렌더링을 막을 수 있다.

간단하게 말해서, 렌더링이 필요하면 useState를 쓰면 되고 아닐 경우 useRef를 써야한다.

useState와 차이

  • 간단히 말하면 useState는 렌더링을 원할 때 useRef는 렌더링을 원하지 않을때 사용한다고 볼 수 있다.
  • 다음과 같은 경우이다.
  • React 공식 문서에 있는 예제에 state를 클릭 했을때 어떻게 되는지 비교하기 위해 코드를 추가했다.
  • alert 창을 닫을 때 useRef를 이용하면 컴포넌트가 렌더링 되지 않고
  • useState를 이용하면 컴포넌트가 다시 렌더링 된다.
import { useRef, useState } from "react";

export default function Ref() {
  const ref = useRef(0);
  const [state, setState] = useState(0);
  function handleClick() {
    ref.current = ref.current + 1;
    alert("You clicked " + ref.current + " times!");
  }

  function handleClickState() {
    setState(state + 1);
    alert("You clicked " + state + " times!");
  }

  return (
    <>
      <button onClick={handleClick}>Click me!</button>
      <button onClick={handleClickState}>State Click me!</button>
    </>
  );
}

useRef를 통해 DOM에 접근

  • 처음 선언을 null로 해준다.
import { useRef } from 'react';

function MyComponent() {
  const inputRef = useRef(null);
  // ...
  • 그리고 가져오고 싶은 DOM 요소에 다음과 같이 적어준다
// ...
  return <input ref={inputRef} />;
  • DOM 요소를 조작하기 위해 선언할 때 초기 값을 null로 주는게 좋은 이유
    • 만약 이런 식으로 선언을 한다면 초기 렌더링 시에만 선언되는 것이 아닌 매번 렌더링이 될 때마다 새롭게 불러오게 된다. → 낭비가 된다
function Video() {
const playerRef = useRef(new VideoPlayer());
// ...
  • 이를 해결하기 위해 보통 초기 상태를 null로 선언한다
function Video() {
const playerRef = useRef(null);
if (playerRef.current === null) {
  playerRef.current = new VideoPlayer();
}
// ...

useRef 타입

  1. useRef<T>(initialValue: T): MutableRefObject<T>;
    • 인자의 타입과 제네릭 타입이 T로 일치하는 경우
  2. useRef<T>(initialValue: T|null): RefObject<T>;
    • 인자의 타입이 null을 허용하는 경우
  3. useRef<T = undefined>(): MutableRefObject<T | undefined>;
    • 제네릭의 타입이 undefined인 경우(타입 제공 x인 경우)
  • 실제로 위와 같이 3개의 타입으로 정의되어 있다.
  • 내가 받아들인 방식
    • 1,3번 → 렌더링이 되지 않는 변수로 선언하고 싶을 때
    • 2번 → 돔을 조작하고 싶을 때

useRef와 let의 차이점은 뭘까?

  • LifeCycle에 있다고 볼 수 있다.
  • let으로 선언한 변수는 state가 변하면 다시 초기화가 된다. 하지만 useRef는 초기화가 되지않고 유지된다.

  • 위 예시를 보면 Ref와 Var가 동일하게 증가한다. 하지만 State의 값을 증가시키는 순간 리렌더링이 되면서 let의 값은 초기화되고, Ref의 값은 state와 같은 LifeCycle을 같기 때문에 상태가 유지된다.

useRef를 props로 넘기고 싶어!!

  • useRef를 props로 넘기는 방법에는 두 가지가 있다.
<Input inputRef={inputRef} />
<Input label="input 컴포넌트  분리" ref={inputRef} />
  1. ref는 예약어이므로 다른 props를 용어로 설정해 넘긴다. → 하지만 이는 ref가 많아질수록 다양한 이름이 등장할 가능성이 높다.
  2. 예약어인 ref를 이용해 넘겨준다.
    • 이 방법은 forwardRef가 필요하다. forwardRef를 이용하면 ref를 이용해 넘길 수 있다.
    • 대신 ref를 받는 자식 쪽에서는 다음과 같은 설정이 추가로 필요하다
    import { forwardRef } from "react";

    const Input = forwardRef(function Input(
      props: { label: string },
      ref: React.ForwardedRef<HTMLInputElement>,
    ) {
      const { label } = props;
      return (
        <div>
          <span>{label}</span>
          <input ref={ref} />
        </div>
      );
    });

    export default Input;
  • 다음과 같이 forwradRef로 감싸고 export를 해주어야 한다.
  • 또 타입 스크립트를 사용하면 ref의 타입을 React.RefObject<HTML 뭐시기>가 아닌 위 예제처럼 React.ForwardRef<HTML 뭐시기>로 선언해줘야 타입 에러가 발생하지 않는다

useRef 사용예시

autofocus VS useRef focus()

  • input tag의 속성중 하나인 autofocus는 렌더링 처음에만 포커스가 잡히게 되는데
  • useRef는 다시렌더링이 일어나도 focus가 잡힌다.

Reference & Additional Resources

profile
의미있는 성장의 태도, 긍정적인 사고를 지닌 Deveolper
post-custom-banner

0개의 댓글