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

hyebin Jo·2022년 7월 29일
0

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개의 댓글