Home [React] useRef 는 언제, 어떻게 쓸까
Post
Cancel

[React] useRef 는 언제, 어떻게 쓸까

useRef

1
const refContainer = useRef(initialValue);

useRef.current 프로퍼티로 전달된 인자(initialValue) 로 초기화된 변경 가능한 ref 객체를 반환한다. 변환된 객체는 컴포넌트의 전 생애주기를 통해 유지될 것이다.

일반적인 유스케이스는 자식에게 명령적으로 접근하는 경우:

1
2
3
4
5
6
7
8
9
10
11
12
13
function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () => {
    // 'current' points to the mounted text input element
    inputEl.current.focus();
  };
  return (
    <>
      <input ref={inputEl} type="text" /> // input태그에 ref 훅을 달았다.
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

본질적으로 useRef.current프로퍼티에 변경 가능한 값을 담고있는 “상자” 같다.

Dom에 접근하는 방법으로 refs 를 사용할 수도 있다. <div ref={myRef} /> 를 사용하여 React 로 ref 객체를 전달한다면, React 는 노드가 변경될 때마다 변경된 DOM 노드에 그것의 .current 프로퍼티를 설정할 것이다.

하지만, ref 속성보다 useRef() 가 더 유용하다. 이 기능은 클래스에서 인스턴스 필드를 사용하는 방법과 유사한 어떤 가변값을 유지하는데에 편리하다.

이것은 useRef() 가 순수 자바스크립트 객체를 생성하기 때문이다. useRef(){current: ...} 객체 자체를 생성하는 것의 유일한 차이점이라면 useRef는 매번 렌더링을 할 때 동일한 ref 객체를 제공한다는 것.

useRef내용이 변경될 때 그것을 알려주지는 않는다 는 것을 주의하자. .current 프로퍼티를 변형하는 것이 리렌더링을 발생시키지는 않는다. React 가 DOM 노드에 ref를 attach 하거나 detach할 때 어떤 코드를 실행하고 싶으면 대신 콜백 ref 를 사용해야 한다.

실제로 사용해보기

JavaScript 를 사용 할 때, 특정 DOM 을 선택하는 상황에 getElementById, querySelector 같은 DOM Selector 함수를 사용해서 DOM 을 선택함.

리액트에서도 가끔 DOM 을 직접 선택해야 하는 상황이 있다. 예를들어 특정 엘리먼트의 크기를 가져와야 한다던자ㅣ, 스크롤바 위치를 가져오거나 설정해야 된다던지, 포커스를 설정해줘야 한다던지 정말 다양한 상황이 있다.

리액트에서는 ref 를 사용하고, 함수형 컴포넌트에서 useRef 라는 Hook 함수를 사용.

초기화 버튼을 클릭했을 때 이름 input 에 포커스가 잡히도록 useRef 를 사용해보겠다.

InputSample.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import React, { useState, useRef } from "react";

function InputSample() {
  const [inputs, setInputs] = useState({
    name: "",
    nickname: "",
  });
  const nameInput = useRef(null); // initialState 에 대해서 null값으로 설정해준다.

  const { name, nickname } = inputs; // 비구조화 할당을 통해 값 추출

  const onChange = (e) => {
    const { value, name } = e.target; // 우선 e.target 에서 name 과 value 를 추출
    setInputs({
      ...inputs, // 기존의 input 객체를 복사한 뒤
      [name]: value, // name 키를 가진 값을 value 로 설정
    });
  };

  const onReset = () => {
    setInputs({
      name: "",
      nickname: "",
    });
    nameInput.current.focus();
  };

  return (
    <div>
      <input
        name="name"
        placeholder="이름"
        onChange={onChange}
        value={name}
        ref={nameInput}
      />
      <input
        name="nickname"
        placeholder="닉네임"
        onChange={onChange}
        value={nickname}
      />
      <button onClick={onReset}>초기화</button>
      <div>
        <b>: </b>
        {name} ({nickname})
      </div>
    </div>
  );
}

export default InputSample;

useRef() 를 사용하여 Ref 객체를 만들고, 이 객체를 우리가 선택하고 싶은 DOM 에 ref 값으로 설정해주어야 한다. 그러면, Ref 객체의 .current 값은 우리가 원하는 DOM 을 가리키게 된다.

useRef 로 컴포넌트 안의 변수 만들기

컴포넌트에서 특정 DOM 을 선택해야 할 때, ref 를 사용했었다. 함수형 컴포넌트에서는 이를 설정 할 때, useRef 를 사용해서 설정했었다.

useRef Hook 은 DOM을 선택하는 용도 외에도 다른용도가 한가지 더 있다. 컴포넌트 안에서 조회 및 수정할 수 있는 변수를 관리하는 것!

useRef 로 관리하는 변수는 값이 바뀐다고 해서 컴포넌트가 리렌더링 되지 않는다. 리액트 컴포넌트에서의 상태는 상태를 바꾸는 함수를 호출하고 나서 그 다음 렌더링 이후로 업데이트 된 상태를 조회할 수 있는 반면, useRef로 관리하고 있는 변수는 설정 후 바로 조회 가능.

이 변수를 사용하여 다음과 같은 값을 관리할 수 있음!

  • setTimeout, setInterval 을 통해서 만들어진 id
  • 외부 라이브러리를 사용하여 생성된 인스턴스
  • scroll 위치
1
2
3
4
5
6
7
8
9
// id 의 예시
const nextId = useRef(4);

const onCreate = () => {
  // 나중에 구현 할 배열에 항목 추가하는 로직
  // ...

  nextId.current += 1;
};

onCreate 함수를 실행할 때 마다 nextId 는 +1 이 된다.

useRef() 를 사용할 때 파라미터를 넣어주면, 이 값이 .current 값의 기본값이 된다. 조작을 원하면 current값을 수정하거나, 조회를 하면 된다.

useRef 로 만들어진 객체는 React가 만든 전역 저장소에 저장되기 때문에 함수를 재 호출하더라도 마지막으로 업데이트한 current 값이 유지된다.

어디서 사용할까…?

useRef 는 값을 저장하기는 하지만, 리렌더가 필요하거나 값이 변경되면 리렌더가 필요할 때는 적합하지 않다. 전역저장소에 저장되면서 리렌더를 유발하지 않는것을 잘 활용하자.

  • 컴포넌트 안에서 조회 및 수정 할 수 있는 변수 관리
  • useRef로 관리되는 변수는 값이 바뀌어도 컴포넌트가 리렌더링 되지 않습니다.
  • 리액트 컴포넌트에서의 상태는 상태를 바꾸는 함수를 호출하고 나서 그 다음 렌더링 이후로 업데이트 된 상태를 조회 할 수 있는 반면, useRef 로 관리하고 있는 변수는 설정 후 바로 조회 할 수 있습니다.

참조

React 공식문서, https://react.vlpt.us/basic/10-useRef.html https://react.vlpt.us/basic/12-variable-with-useRef.html

This post is licensed under CC BY 4.0 by the author.

[JS][Library] Lodash

[Nextjs/Image] Next에서 Imgae 태그