개발하는 무민

[React] Ref 사용법 (forwardRef, ForwardRefRenderFunction, useRef) 본문

Development/React

[React] Ref 사용법 (forwardRef, ForwardRefRenderFunction, useRef)

무민_ 2023. 11. 14. 17:42

Ref란?

리액트에서 DOM 요소나 클래스 컴포넌트의 인스턴스에 직접 접근하기 위한 방법을 제공.

컴포넌트 내부의 특정 DOM 요소에 직접 접근하여, 해당 요소를 조작하거나 해당 요소의 정보를 얻을 수 있다.

Ref는 주로 폼 입력 처리, 포커스 관리, 애니메이션 직접 조작 등에 사용한다.

예시 코드

1. forwardRef를 사용하는 방식

컴포넌트를 생성할 때 바로 Ref를 전달할 수 있는 함수이다.

props와 Ref 두개의 매개변수를 받는다.

주로 함수 컴포넌트에서 사용되며, 컴포넌트 내부에서 ref를 접근할 수 있게 해준다.

→ 외부에서 Ref를 통해 내부의 input 요소에 접근이 가능하다.

 

- ref를 사용한 FancyInput 컴포넌트 예시

import React, { forwardRef } from 'react';

const FancyInput = forwardRef((props, ref) => {
  return <input ref={ref} {...props} />;
});

export default FancyInput;

이 컴포넌트를 사용하는 부모 컴포넌트에서는 다음과 같이 FancyInput에 ref를 전달할 수 있으며, 이를 통해 input 요소에 직접 접근할 수 있다.

 

- 부모 컴포넌트 예시

import React, { useRef, useEffect } from 'react';
import FancyInput from './FancyInput';

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

  useEffect(() => {
    inputRef.current.focus(); // input 요소에 포커스를 맞춤
  }, []);

  return <FancyInput ref={inputRef} />;
}

이 코드를 보면 ParentComponent는 FancyInput에 ref를 전달한다.

FancyInput 내부에서 이 ref는 input 요소와 연결되어, 부모 컴포넌트에서 input 요소에 직접 접근할 수 있게 해준다.

 

2. ForwardRefRenderFunction 를 사용하는 방식

TypeScript 환경에서 React.forwardRef와 함께 사용되는 타입이다.

ref와 함께 사용될 함수 컴포넌트의 타입을 정의하는데 사용한다.

React.forwardRef 내부에서 사용하는 함수를 별도로 정의할 때 사용되며, 타입스크립트의 타입 체킹을 강화한다.

import React, { ForwardRefRenderFunction } from 'react';

interface MyComponentProps {
  // 컴포넌트의 prop 타입 정의
}

const MyComponent: ForwardRefRenderFunction<HTMLDivElement, MyComponentProps> = (props, ref) => {
  return <div ref={ref}>Hello, World!</div>;
}

export default React.forwardRef(MyComponent);

 

  • Ref를 사용하는 일반적인 작업들

부모 컴포넌트에서 자식 컴포넌트에 ref로 직접 접근시에 사용하는 작업들은 다음과 같다.

  1. 포커스 관리: 페이지 로드 시 특정 input 요소에 자동으로 포커스를 맞추거나, 사용자의 액션에 따라 다른 input 요소로 포커스를 이동시키는 작업
  2. 입력값 검증 및 추출 : input 요소의 현재 값을 가져와서 검증하거나 처리하는 작업. 사용자가 입력한 데이터를 가져와 서버로 전송하기 전에 검증(ID, PW 등)하거나 입력 형식에 맞는지 확인
  3. 애니메이션 및 스타일 조작 : 직접적인 DOM 조작을 통해 input 요소의 스타일을 변경하거나 애니메이션 효과를 주는 경우에 사용한다. 예를 들어, 사용자가 입력란에 포커스를 맞추었을 때 입력란의 테두리 색상을 변경하는 등의 작업
  4. 자동완성 기능 : 사용자가 입력값을 시작할 때 관련된 데이터를 자동으로 제시하는 기능을 구현할 때 사용한다. 사용자가 입력하는 동안 input 값이 변경되는 것을 감지해서 관련된 데이터를 제시할 수 있다.
  5. 텍스트 선택 및 조작 : 사용자가 특정 액션을 했을 때 input 내의 텍스트를 전체 선택하거나, 특정 부분의 텍스트를 수정하는 등의 작업을 처리할 수 있다.

위의 작업들은 input 에 대한 직접적인 접근이 필요하기 때문에 ref를 사용하는 것이 일반적인 접근 방식이다.

ref를 사용하면 React의 데이터 흐름 (state, prop) 외부에서도 특정 DOM 요소를 직접 조작할 수 있다.

 

공식문서 참고하기(Ref와 DOM – React)

공식문서에 나온 내용은 다음과 같다.

 

일반적인 React의 데이터 플로우에서 props는 부모 컴포넌트가 자식과 상호작용할 수 있는 유일한 수단이다.

자식을 수정하려면 새로운 props를 전달해서 자식을 다시 렌더링해야 한다.

그러나, 일반적인 데이터 플로우에서 벗어나 직접적으로 자식을 수정해야 하는 경우도 있다.

수정할 자식은 react 컴포넌트의 인스턴스 이거나, DOM 엘리먼트 등일 수 있다.

React에서는 두 경우 모두를 위한 해결책을 제공하고 있다.

 

  • Ref를 사용해야 하는 경우

바람직한 사용 사례는 다음과 같다.

 

- 포커스, 텍스트 선택영역, 혹은 미디어의 재생을 관리할 때.

- 애니메이션을 직접적으로 실행시킬 때.

- 서드 파티 DOM 라이브러리를 React와 같이 사용할 때.

 

선언적으로 해결될 수 있는 문제에서는 ref 사용을 지양하는 것이 좋다. 너무 남용하면 안됨..

예를 들어, Dialog 컴포넌트에서 open()과 close() 메서드를 두는 대신, isOpen이라는 prop을 넘겨주는 것이 좋다.

 

Ref 생성하기

Ref는 React.createRef()를 통해 생성되고 ref 어트리뷰트를 통해 React 엘리먼트에 부착된다.

보통 컴포넌트의 인스턴스가 생성될 떄 Ref를 프로퍼티로서 추가해서 어느곳에서도 Ref에 접근할 수 있게 한다.

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }
  render() {
    return <div ref={this.myRef} />;
  }
}

 

Ref 접근하기

render 메서드 안에서 ref가 엘리먼트에게 전달되었을 때, 그 노드를 향한 참조는 ref의 current 어트리뷰트에 담긴다.

const node = this.myRef.current;

 

등등 Ref에 관련된 내용들이 정리되어 있다.

 

useRef

useRef를 사용하는 방식도 있다!

useRef는 React의 Hook 중 하나로, 컴포넌트 내에서 참조(ref)를 생성하고 관리하는데 사용된다.

이 ref는 DOM 요소에 직접 접근하거나, 컴포넌트의 지속적인 상태를 저장하는 데 사용할 수 있음.

예시

import { useRef } from 'react';
import MyInput from './MyInput.js';

export default function Form() {
  const ref = useRef(null);

  function handleClick() {
    ref.current.focus();
  }

  return (
    <form>
      <MyInput label="Enter your name:" ref={ref} />
      <button type="button" onClick={handleClick}>
        Edit
      </button>
    </form>
  );
}

예시의 Form 컴포넌트에서 useRef는 input 요소에 대한 참조를 생선한다. 이를 통해 handleClick 함수에서 ref.current.focus()를 호출하여 프로그래밍적으로 input 요소에 포커스를 줄 수 있다.

useRef는 주로 컴포넌트 내부에서 DOM 요소에 접근하거나, 렌더링 사이에 지속되어야 하는 값을 저장하는 데 사용됨

 

차이점

알아봤던 세가지의 방식을 정리하자면 다음과 같다.

  • forwardRef: 부모 컴포넌트로부터 받은 ref를 자식 컴포넌트의 내부 DOM 요소나 다른 컴포넌트로 전달할 때 사용한다. 주로 컴포넌트 라이브러리나 고차 컴포넌트를 작성할 때 필요함.
  • ForwardRefRenderFunction : forwardRef와 유사하게, 부모 컴포넌트로부터 받은 ref를 내부 요소로 전달하는 함수형 컴포넌트를 타입스크립트에서 정의할 때 사용한다. 기능은 forwardRef와 비슷하지만, 타입스크립트에서의 정의에 초점을 더 맞췄다고 한다. props와 ref에 대한 타입을 정확하게 지정이 가능함.
  • useRef: 컴포넌트 내에서 ref를 생성하고 관리할 때 사용한다. DOM 요소에 접근하거나 렌더링 사이에 변하지 않는 값을 저장하는 데 적합. 

 

아직 정의 문서를 봐도 잘 모르겠다…

실제 코드에 적용해서 사용해보면서 더 공부해야겠음

 

참고 : https://react.dev/reference/react/forwardRef