카테고리 없음

[React] useRef

ehddkDEV 2024. 10. 7. 22:25

useRef는 리액트 hook의 한 종류이며 ,

reference(참조)의 줄임말로 특정한 DOM요소에 접근이 가능하면서 불필요한 재렌더링을 하지 않는다.

 

ref는 state와 비슷하게 어떠한 값을 저장하는 공간으로 사용된다고 한다.

ref는 UI에 영향을 주지 않고, 특정 이벤트가 트리거 되어있을때 특정 event에 참조가 필요한 경우에 사용한다.

폼 제출과 같은 이벤트가 발생 시, input 요소들의 값에 접근하기 위해 ref.current를 사용할 수 있다는 의미이다.

ref의 변화가 생기면 렌더링이 일어나지 않아 변수값이 유지되는데, 따라서 렌더링과는 무관하게 값이 유지되어야 할 때 사용.

 

그럼 useState가 있는데 언제,왜 UseRef를 사용할까?

 

When

1. Dom요소에 직접 접근

바닐라 JS의 getElementById 처럼 직접 dom에 접근 가능하다.

login form에서 모든 값을 입력하지 않고 버튼을 눌렀을때 특정 input에 focus 된 경우를 본 적이 있을 것이다.

이처럼 , 우리가 직접 input요소를 클릭하지 않아도 focus를 줄때 사용한다!

import React from "react";

type SignUpViewProps = {};

const SignUpView = (props: SignUpViewProps) => {
  const _email = React.useRef<HTMLInputElement>(null);
  const _password = React.useRef<HTMLInputElement>(null);
  const _passwordCheck = React.useRef<HTMLInputElement>(null);
  const _name = React.useRef<HTMLInputElement>(null);

  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();

    console.log({
      email: _email.current?.value,
      password: _password.current?.value,
      passwordCheck: _passwordCheck.current?.value,
      name: _name.current?.value,
    });
  };

  return (
    <div>
      <h1>회원가입</h1>
      <form onSubmit={handleSubmit}>
        <label htmlFor={"email"}>
          이메일
          <input type="email" id={"email"} name={"email"} ref={_email} />
        </label>

        <br />
        <label htmlFor={"password"}>
          비밀번호
          <input
            type="password"
            id={"password"}
            name={"password"}
            ref={_password}
          />
        </label>
        <br />
        <label htmlFor={"passwordCheck"}>
          비밀번호 확인
          <input
            type="password"
            id={"passwordCheck"}
            name={"passwordCheck"}
            ref={_passwordCheck}
          />
        </label>
        <br />
        <label htmlFor={"name"}>
          이름
          <input type="text" id={"name"} name={"name"} ref={_name} />
        </label>
        <br />
        <button type="submit">회원가입</button>
      </form>
    </div>
  );
};

export default SignUpView;

 

이 코드를 보면 useRef를 사용함으로써

email 필드의 값을 참조하기 위해 current.value를 통해 현재 값을 가져올 수 있고, onChange 핸들러를 사용하지 않고도 값을 얻을 수 있기 때문에 코드가 간결해진다!

 

포커스가 변경된다고 해서 컴포넌트가 리렌더링될 필요는 없기 때문에 ref가 적합하다.

 

 

2.렌더링과 관련이 없는 값들을 저장할때

 

import React, { useRef } from 'react';

const Component = () => {
  const dataRef = useRef('');
  //useState인 경우
  // const [data, setData] = useState('');
  
  const fetchData = () => {
    // useRef를 사용하여 컴포넌트의 렌더링에 영향을 주지 않고 데이터를 설정
    const newData = 'bigData...';
    dataRef.current = newData;
    //useState인 경우
    //setData(newData);
  };

  return (
    <div>
      <button onClick={fetchData}>Fetch Data</button>
      <p>Data Length: {dataRef.current.length}</p>
    </div>
  );
};

export default Component;

이렇게 useState 대신에 useRef로 관리를 하면,

데이터 양이 증가하더라도 useRef를 사용하면 컴포넌트의 렌더링 속도에 영향을 주지 않고 데이터를 설정할 수 있다.

 

3. 저장된 이전 값 접근

상태 값이 변경되기 전의 값을 기억하고 접근해야 할 때 ref는 값을 저장할 수 있을 뿐만 아니라 리렌더링을 일으키지 않는다.

import React, { useState, useRef, useEffect } from 'react';

const PreviousValueExample = () => {
  const [count, setCount] = useState(0);
  const prevCountRef = useRef<number>(count);

  useEffect(() => {
    prevCountRef.current = count; // 이전 count 값을 저장
  }, [count]);

  return (
    <div>
      <h1>현재 값: {count}</h1>
      <h2>이전 값: {prevCountRef.current}</h2>
      <button onClick={() => setCount(count + 1)}>증가</button>
    </div>
  );
};

export default PreviousValueExample;

 

따라서 렌더링에 영향을 주지 않고도 이전 값을 유지할 수 있다.!

 

4. 스크롤 관리

스크롤 위치는 UI와 관련된 값이지만, 이 값이 변경될 때마다 컴포넌트를 리렌더링할 필요가 없다.

하지만 특정 스크롤 위치에서 위로가기 버튼이 나오게 해야할 경우에는 ref를 쓰면 안된다.

 

장점

자주 바뀌는 값을 state에 담으면 변경될때 마다 리렌더링이 일어나 성능이 좋지 않기에, ref를 사용함으로써 리렌더링을 막아 성능 향상에 도움이 된다!

 

 

그러면 일반 변수에 담았을때는 ref사용과 어떠한 차이를 보이는지 알아보자!

const App=()=>{

    const count = 0;
    const increment=()=>{
      count +=1;
    }

    return(
       <>
          <p>{count}</p>
          <button onClick={increment}> up! </button>
        </> 
	)
 }

 

버튼을 누르면 {count}에는 무슨 값이 찍힐까?

 

1?

땡 ❌

 

정답은 0이다.

렌더링은 곧 함수를 처음부터 재실행하는 것이기에, 렌더링할때마다 App 컴포넌트에 있는 함수가 다시 호출된다..

그럼 변수들이 다시 초기화가 되기에 const count= 0; 에 의해 count 변수에는 계속해서 0으로 나온다.

 

즉, useRef를 사용함으로써 useState,일반변수와 다르게 리렌더링시에도 초기화가 안되기에 성능향상에도 좋고

ref속성 사용과 함께 dom요소에 접근이 쉽다!