FrontEnd/React

React Hooks -useRef에 대하여

NandaNanda 2024. 3. 26. 23:16

참고:https://www.youtube.com/watch?v=VxqZrL4FLz8&list=PLZ5oZ2KmQEYjwhSxjB_74PoU6pmFzgVMO&index=3

https://hihiha2.tistory.com/19#recentComments  (영상 잘 정리해 놓은글)

아... 이제 알겠다. useRef()로 반환되는 객체의 이름을 nameFocus라고 했을때 nameFocus를 ref속성의 값으로 취하는 태그가 nameFocus객체의 current키의 값이 되는 것이다.

useRef의 구체적인 주요역할 3가지. 
DOM요소에 직접접근, 효율적인 component랜더링과 변수 관리 

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

(반환되는 객체(ref객체)는 유일하고 그 객체가 가지는 'current'키의 값이 바뀔수 있다는 말뜻일 것이다. 그리고 current키의 값이 곧 참조의 대상일 것이다. 즉 current는 현재 참조하는 대상을 가리키는 key이름이다.)

 

useRef는 리액트 훅의 한 종류로, Ref는 reference(참조)의 줄임말이다. 

useRef를 이용하면 특정한 DOM요소에 접근이 가능하며, 불필요한 재렌더링을 하지 않는다는 장점이 있다.

 

1. 형식

1️⃣ 생성

const 변수명 = useRef(초기값)

 

➡️ 이러한 결과값으로, {current:  초기값}  을 지닌 객체가 반환된다.

 

useRef에서 기억할 것은 이러한 current라는 키값을 지닌 프로퍼티가 생성되고, 값에 어떤 변경을 줄때도 이 current를 이용해서 한다는 점이다.

 

이 코드가 곧 변수가 가리키는 ref객체의 current키의 값을 input태그로 하겠다는 뜻이다.

 

2. 특징

 반환된 useRef 객체는 컴포넌트의 전생애주기를 통해 유지가 된다. 

1️⃣(= 컴포넌트가 계속해서 렌더링이 되어도 컴포넌트가 언마운트되기 전까지는 값을 그대로 유지할 수 있다)

2️⃣(= currnet 속성은 값을 변경해도 상태를 변경할 때 처럼 React 컴포넌트가 재렌더링 되지 않는다. )

 

🔫 렌더링과 상관없이, 마운트된 시점부터 언마운트된 시점까지 값을 유지한다 🔫

3. 언제 사용?

1️⃣  저장공간

ref는 state와 비슷하게 어떤 값을 저장하는 저장공간으로 사용된다.(current에 특정 태그값을 저장하는 저장공간이 Ref객체, useRef()의 반환값일 것이다)

즉, Ref의 값을 변화시켰다 해도 리랜더링이 일어나지 않기 때문에 화면의 변화는 찾아볼수 없다. 여기서 Ref의 장점을 찾을 수 있다. 컴포넌트에서 엄청 자주바뀌는 값은 state가 아닌 ref로 둔다면 그 값이 변해도 리랜더링이 일어나지 않으므로 자원을 아낄수 있다.

변경시 렌더링을 발생시키지 말아야하는 값을 다룰때 사용한다

(변화는 감지해야하고 그 변화가 저장, 유지 되어야 하지만, 그 변화가 렌더링을 발생시키면 안될때 useRef가 유용히 사용된다!!)

 

 

2️⃣  DOM요소에 접근

✅ useRef를 사용하면 손쉽게 input에 접근할 수 있다.

바닐라 자바스크립트의 getElementById, querySelector와 비슷하다.

<DOM요소 접근의 대표적인 예>

대표적으로 Input요소를 클릭하지 않아도 focus를 줄때 사용

 

4. 장점

자주 변경되는 값을 state에 담으면, 변경될때마다 재렌더링이 일어나서 성능에 안좋은 영향을 미친다.

하지만 useRef를 이용하면 값이 변경될때마다 렌더링이 일어나지 않는다 ➡️ ⭐️ 성능향상!! ⭐️

 

 

5. 일반 변수와의 차이점

state는 변경될때마다 재렌더링이 일어나고, ref객체의 current키의 값은 변경이 되어도 렌더링이 일어나지 않는다는 점을 알았다.

그러면 일반변수에서 선언한 값과는 어떤 차이가 있을까?(일반변수 역시 값이 바뀌어도 리랜더링이 일어나지 않기 때문에 Ref와 일반변수의 차이점이 무엇인가를 알아보려고 하는 것임)

 

const countVar = 0; 이라는 변수를 선언하고 버튼을 누르면 그값에 +1을 하는 함수를 만들었다고 해보자.

const App = () => {

const countVar = 0;

const increaseVar = () => {
countVar = countVar +1;
}

return (
<div>
<p>Var: {countVar} </p>
<button onClick={increaseVar}> Var올려 </button>
</div>
)

Var올려 버튼을 누르고 렌더링을 해주면 var는 몇이 나올까?

정답은 0이다.

렌더링을 해준다는 것은 함수를 처음부터 다시 실행한다는 것을 의미한다.

그래서 렌더링을 할때마다 App컴포넌트를 나타내는 함수가 다시 불린다. 그러면 함수가 불릴때마다 이 함수 내부에 있는 변수들이 다시 초기화가 된다. 

따라서 렌더링이 될때마다 const countVar = 0; 를 통해서 countVar라는 변수에는 계속해서 0으로 초기화가 된다.

🤔 useRef훅을 이용한 값과의 비교
ref의 값은 컴포넌트의 전생애주기를 통해서 관리되기 때문에, 아무리 컴포넌트가 렌더링 되더라도 언마운트가 되기 전까지는 값을 계속해서 유지한다.

✅ ref는 렌더링이후에도 값이 유지되지만, 변수는 초기화된다.


일반변수, Ref객체의 current키의 값, 두개모두 값이 변해도 리랜더링이 일어나지 않는점은 같다. 하지만 state, props의 변경으로 리랜더링이 일어나면 일반변수는 초기화되지만 Ref객체의 current키의 값은 초기화되지 않는다. 

5. 대표적인 예시

input요소에 focus를 주고 싶을때 많이 사용한다.

ex>로그인 화면에서 id를 입력하는 칸을 클릭하지 않아도 자동적으로 focus가 되어있게 해주면, 키보드만 사용해도 바로 id를 입력할 수 있어서 편리하다.

 

리셋버튼을 누르면 맨앞에 있는 input에 focus가 들어가는 코드를 짜도록 해보자.

앞서서 input여러개 관리하기 연습한 코드에 이어서 만들어보았다.

import React, { useState, useRef } from "react";

const InputSample = () => {
  const [inputs, setInputs] = useState({
    이름: "",
    nickname: "",
  });

  const nameFocus = useRef();

  const { 이름, nickname } = inputs;

  const onChange = (e) => {
    const { value, name } = e.target;
    setInputs({
      ...inputs,
      [name]: value,
    });
  };

  const onReset = () => {
    setInputs({
      이름: "",
      nickname: "",
    });
    nameFocus.current.focus();
  };
  return (
    <div>
      <input
        name="이름"
        placeholder="이름쓰세요"
        onChange={onChange}
        value={이름}
        ref={nameFocus}
      />
      <input
        name="nickname"
        placeholder="닉네임쓰세요"
        onChange={onChange}
        value={nickname}
      />
      <button onClick={onReset}>초기화</button>
      <div>
        <b>값:</b>
        {이름}({nickname})
      </div>
    </div>
  );
};

export default InputSample;

1️⃣  const nameFocus = useRef();

nameFocus라는 변수명을 지어서 useRef()의 초기값을 빈값으로 할당하였다.

 

2️⃣  onReset 함수안에 nameFocus.current.focus()

 const onReset = () => {
    setInputs({
      이름: "",
      nickname: "",
    });
    nameFocus.current.focus();
  };

onReset를 누르면

useRef를 통해 만든 객체인 nameFocus안에 current에 focus()를 준다. (아.... 이 current가 객체의 키인 current였구나...)

3️⃣ input안에 ref 속성값으로 {변수명}을 적는다.

      <input
        name="이름"
        placeholder="이름쓰세요"
        onChange={onChange}
        value={이름}
        ref={nameFocus}
      />

실제로 focus가 일어날 input에 ref라는 속성을 통해 변수명을 전달한다.

 

초기화버튼을 눌렀을때, 위와같이 focus버튼이 첫번째 input에 생긴것을 확인해볼수있다.

useRef란 무엇인지, 그 특징과 사용이유를 중점으로 공부해보았다.

렌더링을 계속해서 발생시키지 않기때문에 성능에 도움이 될 수 있고, ref를 이용해서 쉽게 DOM요소에 접근할 수 있다는 것이 흥미로웠다.

 

 

🤓 useRef 요약 🤓

//생성 
const 변수명 = useRef(초기값)
// {current: 초기값} 을 지닌 객체가 반환됨 

//반환요소에 접근
<input ref={변수명}/>

1️⃣ 변화는 감지하지만 렌더링 발생 X ➡️  성능향상 (state는 변화시, 재렌더링됨)

2️⃣ DOM요소에 손쉽게 접근 (ref속성 사용)

3️⃣ 전생애주기를 통해 유지 (언마운트 되기전까지는 값을 계속 기억함)