프론트엔드/React

[React] useRef는 언제 왜 사용할까? 무한루프 해결방법

s_omi 2024. 1. 26. 22:58
728x90
반응형
SMALL

useRef 

useRef는 함수형 컴포넌트 내에서 사용하며 React Hooks 중에 하나이다.

 

 

사용법

useRef를 사용하기 위해선 먼저 다음과 같이 import를 해주어야 useRef 사용이 가능하다. 

import { useRef } from 'react';

 

이렇게 import 된 useRef는 코드에서 다음과 같이 사용된다. 

const ref = useRef(value);

 

이때 ref 에는 객체가 반환되게 되는데 그때 반환된 객체는 다음과 같이 생겼다. 

{ current: value }

 

다음과 같이 useRef의 인자로 넣어준 초기값은 ref 객체 내의 current에 저장되게 된다. 

또한 ref 객체는 언제든지 수정이 가능하여 원하는 값으로 바꿔줄 수 있다. 

const ref = useRef("valueeeee");  // { current: "valueeeee" }
ref.current = "vvvvalueeeee";     // { current: "vvvvalueeeee" }

 

useRef를 사용하여 반환된 객체는 컴포넌트가 계속해서 렌더링이 되어도 값을 유지한다. 다만 언마운트가 되면 리셋된다.

 

 

사용 이유

useRef는 다음과 같은 상황에서 주로 사용한다.

 

1. useRef는 컴포넌트의 렌더링을 발생시키길 원치 않는 값을 저장하는 저장공간으로써 유용하다.

 

컴포넌트 내의 state 값이 변하게 되면 자동으로 컴포넌트가 다시 렌더링된다. 이때 함수형 컴포넌트 같은 경우 렌더링되게 되면 컴포넌트 내부 변수들이 전부 초기화가 되는데 이렇게 변수의 값이 초기화되는 것을 원치 않는 경우 useState 대신 useRef를 사용하면 좋다. 

 

useSatae와 달리 useRef 내에 있는 값은 아무리 변경해도 컴포넌트에는 다시 렌더링되지 않는다. useRef를 사용하게 된다면 컴포넌트의 불필요한 리렌더링이 사라지게 되고 컴포넌트 내의 변수들의 값도 유지되게 된다. 

 

또한 컴포넌트 내의 state 값이 변경되어 컴포넌트가 렌더링되어도 useRef 내에 있는 값은 유지되게 된다.

즉, 변경 시 렌더링을 발생시키지 않아야 하는 값을 다룰 때 주로 useRef를 사용한다.

 

 

2. useRef를 통해 실제로 DOM 요소에 접근하여 여러가지 일들을 할 때 유용하다.

 

대표적으로 회원가입 등의 페이지에서 사용자가 input 요소를 클릭하지 않아도 input 요소에 focus를 주고 싶을 때 주로 사용한다. 

 

[React] useRef를 통해 DOM요소에 직접 접근하기

 

mi-dairy.tistory.com

 

 

사용 예시

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

const App = () => {
  const [value, setValue] = useState(0);
  const valueRef = useRef(0);
  let valuee = 0;
    
  const increaseState = () => {
    setValue(value + 1);
  }
    
  const increaseRef = () => {
    valueRef.current = valueRef.current + 1;
  }
    
  const increase = () => {
    valuee = valuee + 1;
  }
    
  return (
    <div>
      <p>State :: {value}</p>
      <p>Ref :: {valueRef.current}</p>
      <p>let :: {valuee}</p>
      <button onClick={increaseState}>state + 1</button>
      <button onClick={increaseRef}>ref + 1</button>
      <button onClick={increase}>let + 1</button>
    </div>
  );
};

 

위의 코드를 실제로 실행시키게 되면  state+1  버튼을 눌렀을 때는 value의 값이 바뀌면서 웹에 값이 바로 바로 반영이 되는데  ref+1  버튼을 눌렀을 때는 valueRef.current의 값이 바뀌지 않고 웹에 값이 바로 바로 반영이 되지 않는 부분을 볼 수 있다. 또한  let+1  버튼을 눌려도 변수 valuee의 값이 0에서 고정되어 있는 것을 볼 수 있다. 

 

왜 그런 것일까?


 state+1  버튼을 누르게 되면 value 값이 변하게 되어 버튼을 누를 때마다 컴포넌트가 렌더링되게 된다. 그러면 컴포넌트 자체가 새로 렌더링되기 때문에 웹에서 렌더링된 컴포넌트를 불러오므로 value의 최신 값을 반영한 웹을 볼 수 있다.

 

하지만 useRef를 사용한 valueRef.current의 경우 값이 변해도 컴포넌트가 새로 렌더링되지 않는다. 그렇기 때문에  ref+1  버튼을 눌렀을 때 내부적으로는 값이 변하고 있어도 렌더링되지 않아 웹에 최신 값이 반영이 되지 않는다. 

그래서 이때 새로고침을 하여 렌더링하게 되면 valueRef.current의 최신 값을 볼 수 있다.

 

단순 변수인 valuee 같은 경우는 함수 내에서 초기화를 한다.  state+1  버튼을 누르게 되면 함수 전체가 렌더링하게 되고 단순 변수는 다시 초기화하게 되므로 초기값으로 돌아간다. 이와 달리  ref+1  버튼을 누르게 되면 useRef는 리렌더링하지 않기 때문에 valuee의 변수 값은 그대로 유지하게 된다. 

새로고침도 렌더링을 하므로 valuee 값은 변해도 웹에서는 변한 값을 보기 힘들다.

 

 

useState useEffect 무한루프에 걸리는 이유

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

const App = () => {
  const [value, setValue] = useState(0);
    
  useEffect(() => {
    setValue(value + 1);
  });
    
  return (
    <div>
      <p>State :: {value}</p>
      <button 
        onClick={() => setValue(value + 1)}
      >
        state + 1
      </button>
    </div>
  );
};

 

위와 같은 코드를 실행했을 경우 우리는 무한루프에 빠지게 된다.

 

이유?

 

사용자가  state + 1  버튼을 누르게 되면 useState의 value 값이 변하게 되므로  렌더링으로 인해 useEffect 함수의 내용이 실행되게 된다. 그러나 현재 useEffect 함수 내에도 useState의 value 값을 변하게 만드는 코드가 있어 value 값이 변하게 되면 또 useEffect 함수를 실행되게 되고 ... 이렇게 useState의 value 값 변경 ↔ useEffect 함수 실행이 반복되게 되어 무한루프에 빠지게 된다. 

 

해결방안!

useRef 를 사용하면 된다!

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

const App = () => {
  const [value, setValue] = useState(0);
  const valueRef = useRef(0);
    
  useEffect(() => {
    valueRef.current = valueRef.current + 1;
  });
    
  return (
    <div>
      <p>State :: {value}</p>
      <button 
        onClick={() => setValue(value + 1);
       >
         state + 1
       </button>
    </div>
  );
};

 

다음과 같이 useRef를 사용하면 값이 변경되어도 렌더링이 되지 않으므로 값은 계속해서 잘 늘어나지만 무한루프에 빠지지 않게 된다. 

 

 


출처 : 유튜브 별코딩 (직접 듣기 강추!)

728x90
반응형
LIST