리액트를 다루는 기술 5장 - ref: DOM에 이름 달기

sh·2022년 8월 2일
0
post-thumbnail

ref

<div id="my-element"></div>

특정 DOM 요소에 어떤 작업을 해야 할 때 HTML에서 id를 사용해 DOM에 이름을 다는 것처럼 리액트 프로젝트 내부에서 DOM에 이름을 다는 방법

어떤 상황에서 사용해야 할까?

DOM을 꼭 직접적으로 건드려야 할 때

예제 컴포넌트(클래스형) 생성

import React, { Component } from "react";
import "./ValidationSample.css";

class ValidationSample extends Component {
  state = {
    password: "",
    clicked: false,
    validated: false,
  };

  handleChange = (e) => {
    this.setState({
      password: e.target.value,
    });
  };

  handleButtonClick = () => {
    this.setState({
      clicked: true,
      validated: this.state.password === "0000",
    });
  };
  render() {
    return (
      <div>
        <input
          type="password"
          value={this.state.password}
          onChange={this.handleChange}
          className={
            this.state.clicked
              ? this.state.validated
                ? "success"
                : "failure"
              : ""
          }
        />
        <button onClick={this.handleButtonClick}>검증하기</button>
      </div>
    );
  }
}

export default ValidationSample;

DOM을 꼭 사용해야 하는 상황

  • 특정 input에 포커스 주기
  • 스크롤 박스 조작하기
  • Canvas 요소에 그림 그리기

ref 사용

사용하는 방법은 두 가지

1. 콜백 함수

ref를 달고자 하는 요소에 ref라는 콜백 함수를 props로 전달한다.
이 콜백 함수는 ref 값을 파라미터로 전달 받고 함수 내부에서 파라미터로 받은 ref를 컴포넌트의 멤버 변수로 설정해준다.

<input ref={(ref) => {this.input=ref}} />

위와 같이 하면 this.input은 input 요소의 DOM을 가리킨다.
ref의 이름은 원하는 것으로 지정가능 this.이름 = ref

2. createRef

리액트에 내장되어 있는 createRef함수 사용 ( v16.3 부터 도입)

import React, { Component } from "react";

class RefSample extends Component {
  input = React.createRef();
  
  handleFocus = () => {
    this.input.current.focus();
  }
  
  render() {
    return (
      <div>
      	<input ref={this.input} />
	  </div>
	);
  }
}

export default RefSample;
  • 컴포넌트 내부에서 멤버 변수로 React.createRef()를 담아 준다.
  • 해당 멤버 변수를 ref를 달고자 하는 요소에 ref props로 넣어준다.

ref를 설정해 준 DOM에 접근하려면 this.input.current를 조회한다.


컴포넌트에 ref 달기

주로 컴포넌트 내부에 있는 DOM을 컴포넌트 외부에서 사용할 때 쓴다.

사용법

<MyComponent
	ref={(ref) => {this.myComponent=ref}}
/>

MyComponent 내부의 메서드 및 멤버 변수에도 접근할 수 있게 된다.

실습 진행 순서
1. ScrollBox 컴포넌트 만들기
2. 컴포넌트에 ref 달기
3. ref를 이용하여 컴포넌트 내부 메서드 호출하기

컴포넌트 초기 설정

// ScrollBox.js
import React, { Component } from "react";

class ScrollBox extends Component {
  render() {
    const style = {
      border: "1px solid black",
      height: "300px",
      width: "300px",
      overflow: "auto",
      position: "relative",
    };

    const innerStyle = {
      width: "100%",
      height: "650px",
      background: "linear-gradient(white,black)",
    };

    return (
      <div
        style={style}
        ref={(ref) => {
          this.box = ref;
        }}
      >
        <div style={innerStyle}></div>
      </div>
    );
  }
}

export default ScrollBox;

최상위 DOM에 ref를 달아 준다.

컴포넌트에 메서드 생성

컴포넌트에 스크롤바를 맨 아래쪽으로 내리는 메서드 scrollToBottom을 생성할 것

  • scrollTop : 세로 스크롤바 위치(0~350)
  • scrollHeight: 스크롤이 있는 박스 안의 div 높이(650)
  • clientHeight: 스크롤이 있는 박스의 높이(300)
 scrollToBottom = () => {
    const { scrollHeight, clientHeight } = this.box;

    this.box.scrollTop = scrollHeight - clientHeight;
 };

컴포넌트에 ref 달고 내부 메서드 사용

App 컴포넌트에서 ScrollBox에 ref를 달고 버튼을 만들어 누르면, ScrollBox 컴포넌트의 scrollToBottom 메서드를 실행하도록 한다.

// App.js
import ScrollBox from "./ScrollBox";
import { Component } from "react";

class App extends Component {
  render() {
    return (
      <div>
        <ScrollBox ref={(ref) => (this.scrollBox = ref)} />
        <button
          onClick={() => {
            this.scrollBox.scrollToBottom();
          }}
        >
          맨 밑으로
        </button>
      </div>
    );
  }
}

export default App;

주의사항
onClick={this.scrollBox.scrollToBottom}로 작성해도 틀린 것은 아니다.
하지만 컴포넌트가 처음 렌더링될 때는 this.scrollBox값이 undefined 이므로 this.scrollBox.scrollBottom 값을 읽어오는 과정에서 오류가 발생한다.
화살표 함수 문법을 사용해 아예 새로운 함수를 만들고 그 내부에서 메서드를 실행하면, 버튼을 누를 때 (이미 한번 렌더링해서 this.scrollBox 를 설정한 시점) this.scrollBox.scrollToBottom 값을 읽어 와서 실행하므로 오류가 발생하지 않는다.



함수형 컴포넌트에서는 useRef라는 Hook 함수를 사용한다! >> 8장에서

0개의 댓글