리액트 공식문서 스터디 6일차 - Ref와 DOM

hyebin Jo·2022년 7월 29일

Ref와 DOM

일반적인 React 데이터 플로우에서, 자식을 수정하려면 새로운 props를 전달하여 자식을 다시 렌더링해야 합니다. 그러나 일반적인 데이터 플로우에서 벗어나 직접적으로 자식을 수정해야 하는 경우 Ref를 사용합니다.

  • Ref 생성하기
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef(); //Ref는 React.createRef()를 통해 생성되고
  }
  render() {
    return <div ref={this.myRef} />; //ref 어트리뷰트를 통해 React 엘리먼트에 부착됩니다.
  }
}
  • Ref에 접근하기
const node = this.myRef.current;
//render 메서드 안에서 ref가 엘리먼트에게 전달되었을 때, 
//그 노드를 향한 참조는 ref의 current 어트리뷰트에 담기게 됩니다.

📌DOM 엘리먼트에 Ref 사용

React.createRef()로 생성된 ref의 current 프로퍼티 값은 ref를 전달받은 DOM 엘리먼트 입니다.

export class CustomTextInput extends React.Component {
  constructor(props) {
    super(props);
    this.textInput = React.createRef(); // ref 생성
    this.focusTextInput = this.focusTextInput.bind(this);
  }

  focusTextInput() {
    this.textInput.current.focus();
  } //DOM 노드를 얻기 위해 "current" 프로퍼티에 접근하고, DOM API를 사용하여 <input/> 엘리먼트에 포커스

  render() {
    //⭐생성자에서 생성한 `this.textInput` ref를 <input/> 엘리먼트와 연결
    return (
      <div>
        <input type="text" ref={this.textInput} />
        <input type="button" value="Focus the text input" onClick={this.focusTextInput} />
      </div>
    );
  }
}

📌클래스 컴포넌트에 ref 사용

import { CustomTextInput } from "./CustomTextInput";

export class AutoFocusTextInput extends React.Component {
  constructor(props) {
    super(props);
    this.textInput = React.createRef(); //ref 생성
  }

  componentDidMount() { 
    this.textInput.current.focusTextInput();
  } //CustomTextInput 컴포넌트의 인스턴스에 접근하여 focusTextInput 메서드를 호출
  //CustomTextInput 컴포넌트의 인스턴스가 마운트 된 이후에 즉시 포커스

  render() {
    return <CustomTextInput ref={this.textInput} />;
  } //⭐생성자에서 생성한 `this.textInput` ref로 CustomTextInput 컴포넌트의 인스턴스에 접근
}

주의!! 위 코드는 CustomTextInput가 클래스 컴포넌트일 때에만 작동합니다.

📌Ref와 함수 컴포넌트

함수 컴포넌트는 인스턴스가 없기 때문에 함수 컴포넌트에 ref 어트리뷰트를 사용할 수 없습니다.

function MyFunctionComponent() {
  return <input />;
}

class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.textInput = React.createRef();
  }
  render() {
    // 이 코드는 동작하지 않습니다.
    return (
      <MyFunctionComponent ref={this.textInput} />
    );
  }
}

다만 함수컴포넌트 안에서 ref를 사용해서 DOM 엘리먼트나 클래스 컴포넌트의 인스턴스에 접근하는것은 가능합니다.

function CustomTextInput(props) {
  const textInput = useRef(null); //ref생성

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

  return ( //DOM 엘리먼트에 접근
    <div>
      <input
        type="text"
        ref={textInput} /> 
      <input
        type="button"
        value="Focus the text input"
        onClick={handleClick}
      />
    </div>
  );
}

📌콜백 ref

ref를 설정하기 위한 또 다른 방법인 콜백 ref를 사용할 때에는 ref 어트리뷰트에 React.createRef()를 통해 생성된 ref를 전달하는 대신, 함수를 전달합니다.
전달된 함수는 컴포넌트의 인스턴스나 DOM 엘리먼트를 인자로서 받습니다.

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

    this.textInput = null;

    //컴포넌트의 인스턴스가 마운트 될 때 ref 콜백을 DOM 엘리먼트와 함께 호출합니다.
    this.setTextInputRef = (element) => {
      this.textInput = element; //DOM 노드의 참조를 인스턴스의 프로퍼티에 저장
    };

    this.focusTextInput = () => {
      if (this.textInput) this.textInput.focus();
    };
  }

  componentDidMount() {
    this.focusTextInput();
  }

  render() {
    // text 타입의 input 엘리먼트의 참조를 인스턴스의 프로퍼티
    // (예를 들어`this.textInput`)에 저장하기 위해 `ref` 콜백을 사용합니다.
    return (
      <div>
        <input type="text" ref={this.setTextInputRef} />
        <input type="button" value="Focus the text input" onClick={this.focusTextInput} />
      </div>
    );
  }
}
//콜백 Ref도 다른 컴포넌트에 전달할 수 있습니다.
function CustomTextInput(props) {
  return (
    <div>
      <input ref={props.inputRef} />
    </div>
  );
}

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

0개의 댓글