[React] ref와 useRef는 어떻게 사용하나

파송송계란빡 ㅣ 2023. 6. 11. 19:45

useRef란?

  • useRef는 React에서 제공하는 훅(Hook)
  • 컴포넌트에서 "참조"할 수 있는 변수를 생성하고 유지
    • { current : value }
  • useRef를 사용하면 컴포넌트의 렌더링과 관련된 사이드 이펙트와 관계 없이 값이 유지한다.
  • useRef를 사용하여 생성된 변수는 current 속성을 통해 접근할 수 있음
    • 이 변수는 컴포넌트의 생명주기 동안 유지되며, 값을 변경해도 컴포넌트의 리렌더링을 트리거하지 않음
    • 컴포넌트가 계속해서 렌더링해도, 컴포넌트가 unmound 되기 전까지는 값을 그대로 유지

useRef의 주요 사용 용도

  • 저장용도
    • state는 변화가 생기면 렌더링이 되고, 컴포넌트 내부 변수들 초기화가 일어남
    • Ref의 변화는 렌더링이 일어나지 않음, 변수들의 값이 유지가 된다
      • State의 변화로 렌더링이 발생해도 Ref의 값은 그대로 유지한다.
  • DOM 요소에 접근
    • useRef를 사용하여 DOM 요소를 참조하고, 해당 요소에 접근하여 속성을 변경하거나 메서드를 호출
    • 엘리먼트에 ref 속성 추가 <input ref={inputRef} />
    • 예를 들어 inputRef.current.focus()를 호출하여 input 요소에 초점을 맞출때 사용
  • 이전 값 기억
    • useRef를 사용하여 이전 값을 저장하고, 이전 값과 현재 값을 비교하거나 이전 값에 기반하여 작업을 수행할 수 있다. 이는 컴포넌트가 리렌더링될 때 이전 값과 현재 값 간의 차이를 확인하는 데 유용 수 있습니다.

useRef의 동작 원리

  • useRef 함수 호출: useRef를 호출하여 참조 객체를 생성.
    • 일반적으로 const ref = useRef(initialValue)와 같은 형태로 사용
    • initialValue는 초기 값으로, 생성된 참조 객체의 current 속성에 저장
  • 참조 객체 반환: useRef 함수는 생성된 참조 객체를 반환
    • 이 객체는 { current: initialValue }와 같은 구조를 가지며, current 속성에 초기 값이 저장됩니다.
  • 참조 객체 사용: 반환된 참조 객체를 변수에 할당하거나 컴포넌트의 상태로 사용
    • ref.current를 통해 초기 값 또는 변경된 값을 읽거나 수정 가능
  • 참조 객체의 current 속성 사용: ref.current를 사용하여 참조 객체의 값을 읽거나 수정합니다. 이 값을 통해 컴포넌트의 렌더링 중에도 값을 유지하고, 참조된 DOM 요소나 외부 라이브러리와 상호작용할 수 있음

useRef 중요점

  • ref.current 값을 변경하여도 React는 해당 값을 변경된 것으로 인식하지 않음
    • 컴포넌트의 리렌더링은 상태(state)의 변경이나 프롭스(props)의 변경에 의해서만 트리거되므로, ref.current의 변경은 리렌더링을 발생시키지 않음
    • 따라서 useRef를 사용하여 생성한 변수는 값의 변경이 컴포넌트의 렌더링과 직접적으로 연결되지 않음
  • 이를 통해 useRef는 일종의 "포인터" 역할을 수행하며, 컴포넌트의 생명주기 동안 유지되는 값이나 객체에 접근하고 변경할 수 있도록 해줌

useRef 구현 뜯어보기

useRef 함수 구현 부분 확인

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

function ExampleComponent() {
    const inputRef = useRef("초기값");

    console.log(useRef);   //useRef 출력

    return (
        <div>
            <input type="text" ref={inputRef}></input>
            <button>초점맞추기</button>
        </div>
    );
}

export default ExampleComponent;
  • useRef 함수 출력하고 디버깅으로 확인하면 useRef() 함수 구조는 아래와 같이 생겼음
  • mountRef() 함수를 반환하고 있다.

  • mountRef() 함수에서는 current: initialValue를 선언해 주고 반환해주는 부분이 있음

  • hook 객체에 추가도 해준다.

useRef 반환값 확인해보기

  • useRef() 함수에서 반환한 값을 다시 const inputRef에 선언해서 보면 current값이 존재하는 것을 볼 수 있음
  • input 엘리먼트에 ref={inputRef} ref 속성을 선언해주면 ref에 { current: input } 이렇게 input 값이 들어가는 것을 확인 할 수 있다.
import React, { useEffect, useRef } from "react";

function ExampleComponent() {
    const inputRef = useRef(null);

    const handleClick = () => {
        console.log(inputRef);
    };

    return (
        <div>
            <input type="text" ref={inputRef}></input>
            <button onClick={handleClick}>초점맞추기</button>
        </div>
    );
}

export default ExampleComponent;
  • inputRef를 출력해보니 inputRef.currnet 속성이 존재한다.

UseRef 예시

useRef 예시1 - 리렌더링 되지않음

  • state 값은 변경될 때마다 리렌더링 된다.
  • 하지만 ref.current 값은 변경되어도 리렌더링 되지 않는다.
    • 매번 값이 변경될 때마다 리렌더링 되지 않아야하는 상황에서 사용하기에 유용하다.
import { useState, useRef } from "react";

function App() {
    const [count, setCount] = useState(0);
    const countRef = useRef(0);

    console.log("렌더링");

    const increaseCountState = () => {
        setCount(count + 1);
    };

    const increaseCountRef = () => {
        countRef.current = countRef.current + 1; //현재 Ref.current 값 + 1
        console.log("Ref ->", countRef);
    };

    return (
        <div>
            <p>State : {count}</p>
            <p>Ref : {countRef.current}</p>
            <button onClick={increaseCountState}>State 올려</button>
            <button onClick={increaseCountRef}>Ref 올려</button>
        </div>
    );
}

export default App;

useRef 예시2 - Dom 요소에 직접 접근1

- ref 속성에 useRef 값을 추가해주면 current 값에 input 요소가 추가된다. - 이를 통해서 input 요소에 접근 가능하다. - input 엘리먼트에 직접 접근해서 .focuse() 실행시킬 수 있다. - input의 value도 접근해서 입력한 값을 가져올 수도 있다.

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

function App() {
    const inputRef = useRef();

    useEffect(() => {
        console.log(inputRef);
        inputRef.current.focus();
    }, []);

    const login = () => {
        alert(`환영합니다 ${inputRef.current.value}`);
        inputRef.current.focus();
    };

    return (
        <div>
            <input ref={inputRef} type="text" placeholder="사용자이름" />
            <button onClick={login}>로그인</button>
        </div>
    );
}

export default App;

useRef 예시3 - Dom 요소에 직접 접근2

  • document.activeElement는 현재 어디에 포커스가 들어가 있는지 확인 할 수 있다.
  • document.activeElement
  • 초기화 버튼을 누르면 포커스가 초기화 버튼에 그대로 남아있게 된다.

  • 이름 input에 포커스를 옮기기 위해서 ref를 이용한다.
  • ref를 사용 할 때에는 useRef 라는 Hook 함수를 사용한다.
  • useRef()를 사용하여 Ref 객체를 만들고, 이 객체를 선택하고 싶은 DOM 에 ref 값으로 설정해준다.
  • 그러면, Ref 객체의 .current 값은 우리가 원하는 DOM 을 가르키게 된다.
const nameInput = useRef();

const onReset = () => {
        setInputs({
            name: '',
            nickName: '',
        })

        console.log(nameInput);
    };

...

<input name="name" placeholder="이름" onChange={onChange} value={name} ref={nameInput}/>

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

function InputSample() {
  const [inputs, setInputs] = useState({
    name: '',
    nickname: ''
  });
  const nameInput = useRef();

  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;

 

📚 참고

chatGPT - chat.openai.com

벨로프 - useRef 로 특정 DOM 선택하기 : https://react.vlpt.us/basic/10-useRef.html

React Hooks에 취한다 - useRef 완벽 정리 1# 변수 관리 | 리액트 훅스 시리즈 : https://www.youtube.com/watch?v=VxqZrL4FLz8&t=376s ← 강추

[React] ref와 useRef는 어떻게 사용하나