[React] ref (React의 DOM, React 컴포넌트의 인스턴스 참조)

Featured image

일반적으로 React 에서의 UI 제어 방식은 DOM node 에 reference를 걸어 제어를 하는 대신, 부모에서 자식으로 props를 전달하여 제어하는 방식으로 동작한다.

그러나 개발 중에는 전형적인 데이터 플로우 이외에 자식을 직접적으로 수정해야할 경우가 오게된다.(DOM 요소, React 인스턴스 모두 포함)

이때 Ref를 사용하면, DOM 요소나 React 인스턴스에 reference를 걸어 직접적으로 제어하거나 수정할 수 있다.

Ref 생성

React 16.3 이상의 버전

React 16.3 이상의 버전에서는 React.createRef() 를 사용하여 Ref 를 생성하고, ref 라는 attribute를 사용하여 React element에 생성한 ref 참조를 붙여준다.

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }

  render() {
    return <div ref={this.myRef} />;
  }
}

React 16.3 이전의 버전

그 이전 버전에서는 ref를 전달하여 참조하는 대신 함수를 전달하는 콜백 패턴 방식을 사용한다.

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = null;
  }

  render() {
    // div 엘리먼트의 참조를 인스턴스의 프로퍼티(this.myRef)에 저장하기 위해 `ref` 콜백을 사용
    return <div ref={(ref) => {this.myRef = ref;}} />;
  }
}

참고 (ref 생성 시점)

컴포넌트의 인스턴스가 마운트 될 때 React는 ref에 DOM 노드가 참조되어 지고. 마운트가 해제될 때, ref의 DOM 노드가 사라지고 다시 null이 된다. componentDidMount 또는 componentDidUpdate 전에 ref 수정(참조) 작업이 진행된다.

Ref 접근

React 16.3 이상의 버전

DOM element 에 ref를 생성한 경우 해당 DOM 노드에 대한 참조는 ref의 current attribute에 담기게 된다.

class CustomTextInput extends React.Component {
  constructor(props) {
    super(props);
    this.textInput = React.createRef();
  }

  focusTextInput = () => {
    // DOM 노드를 얻기 위해 "current" 프로퍼티에 접근
    this.textInput.current.focus();
  }

  render() {
    return (
      <div>
        <input type="text" ref={this.textInput} />
      </div>
    );
  }
}

클래스 컴포넌트에 ref를 사용할 경우에는 ref 객체는 마운트된 컴포넌트의 인스턴스를 가르킨다. 인스턴스 이므로 해당 컴포넌트의 다른 함수나 데이터들을 가져올 수 있다.

(클래스 컴포넌트 일 경우에만 사용할 수 있으며, 함수형 컴포넌트는 인스턴스가 없기 때문에 ref를 사용할 수 없다.)

class AutoFocusTextInput extends React.Component {
  constructor(props) {
    super(props);
    this.textInput = React.createRef();
  }

  componentDidMount() {
    this.textInput.current.focusTextInput();
  }

  render() {
    return (
      <CustomTextInput ref={this.textInput} />
    );
  }
}

React 16.3 이전의 버전

16.3 이전의 버전에서는 current를 사용하지 않고 참조된 인스턴스 프로터피를 그대로 사용하면 된다.

class CustomTextInput extends React.Component {
  constructor(props) {
    super(props);

    this.textInput = null;

    this.focusTextInput = () => {
      // DOM API를 사용하여 text 타입의 input 엘리먼트를 포커스합니다.
      if (this.textInput) this.textInput.focus();
    };
  }

  componentDidMount() {
    this.focusTextInput();
  }

  render() {
    return (
      <div>
        <input type="text" ref={(ref) => {this.textInput = ref;}} />
      </div>
    );
  }
}

Reference