Jun 개발노트

Ref와 DOM

2020-11-29

Ref는 render 메서드에서 생성된 DOM 노드나 React 엘리먼트에 접근하는 방법

Ref의 역할

  • 일반적인 데이터 플로우에서 벗어나 직접적으로 자식을 수정해야 할 경우
    • 수정할 자식이 React 컴포넌트 인스턴스나, DOM 엘리먼트일 수도 있다
  • (일반적인 데이터 플로우) 자식을 수정하려면, 새로운 Props를 전달하여 자식을 다시 렌더링
  • Dialog 컴포넌트에서 open / close 함수를 구현하는 대신 isOpen props를 전달하여 관리

Ref 사용처

  • 포커스, 텍스트 선택영역, 혹은 미디어의 재생을 관리할 때
  • 애니메이션을 직접적으로 실행시킬 때
  • 서드 파티 DOM 라이브러리를 React와 같이 사용할 때

Ref 생성

  • 컴포넌트의 인스턴스가 마운트 될 때 React는 ref 콜백을 DOM 엘리먼트와 함께 호출합니다.
  • 컴포넌트가 마운트될 때 React는 current 프로퍼티에 DOM 엘리먼트를 대입
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }
  render() {
    return <div ref={this.myRef} />;
  }
}

Ref에 접근하기

  1. HTML Element
  • ref.current 안 HTML 엘리먼트 기본 메서드 호출 및 상태를 변경할 수 있다.
class CustomTextInput extends React.Component {
  constructor(props) {
    super(props);
    this.textInput = React.createRef();
    this.focusTextInput = this.focusTextInput.bind(this);
  }

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

  render() {
    return (
      <div>
        <input
          type="text"
          ref={this.textInput} />
        <input
          type="button"
          value="Focus the text input"
          onClick={this.focusTextInput}
        />
      </div>
    );
  }
}
  1. Class Component
  • ref.current 안 component 인스턴스로 메서드 호출 및 상태를 변경할 수 있다.
class AutoFocusTextInput extends React.Component {
  constructor(props) {
    super(props);
    this.textInput = React.createRef();
  }

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

  render() {
    return (
      <CustomTextInput ref={this.textInput} />
    );
  }
}
  1. Functional Component
  • 함수 컴포넌트는 인스턴스를 생성하지 않는 때문에, React.creatRef()를 사용 할 수 없다.
  • hook의 forwardRef를 사용하여 구현 할 수 있다.

Ref 수정/해제 시기

  • 수정 : componentDidMount / componentDidUpdate 메서드가 호출되기 전
  • 삭제 : 컴포넌트의 마운트가 해제될 때 current 프로퍼티를 다시 null

부모 컴포넌트에서 자식 컴포넌트의 DOM 노드에 접근하려 하는 경우

  • 자식 컴포넌트의 캡슐화를 파괴하기 때문에 권장되지 않는다.
  • 자식 컴포넌트의 DOM 노드를 포커스하는 일이나, 크기 또는 위치를 계산하는 일 등을 할 때는 효과적인 방법
  • 함수형 컴포넌트는 React.forwardRef를 사용하거나, 16.2 이전일 경우 아래와 같이 ref를 설정할 수 있다.
function CustomTextInput(props) {

  return (
    <div>
      <input ref={props.inputRef} />
    </div>
  );
}

class Parent extends React.Component {
  render() {
    return (
      <CustomTextInput
        inputRef={el => this.inputElement = el}
      />
    );
  }
}