5장 ref DOM에 이름달기


HTML 에서 id를 사용하여 DOM에 이름 다는 것처럼 리액트 프로젝트 내부에서 DOM 에 이름을 다는 방법 있음. 그것이 바로 ref(reference)

❓ JSX에 id 할당해서 사용하면 안됨?
💡 컴포넌트를 여러번 사용한다면, id 같은 DOM 이 여러개 생기게 됨

ref를 사용해야하는 상황?

DOM을 직접적으로 건드려야할 때 ref를 사용해라
특정 password가 입력되면 비밀번호의 일치에 따라 입력창의 색깔이 변하는 페이지를 써봤다.

class ValidationSample extends Component {
  state = {
    password: "",
    clicked: false,
    validate: false,
  };
  handleChange = (e) => {
    this.setState({
      [e.target.name]: e.target.value,
    });
  };
  handleClick = () => {
    this.checkValidation();
    this.setState({
      password: "",
    });
  };
  checkValidation = () => {
    if (password == "0000") validate = true;
    else validate = false;
  };
  render() {
    let { password, clicked, validate } = this.state;
    return (
      <div>
        <input
          type="password"
          name="password"
          onChange={handleChange}
          className={clicked ? "" : validate ? "failure" : "success"}
        />
        <button onClick={handleClick}>validate</button>
      </div>
    );
  }
}

ref 사용

ref를 사용하는 방법에는 두가지가 있음.

  1. 콜백 함수를 통한 ref
  2. createRef를 통한 ref

콜백함수를 통한 ref

ref 달고자 하는 요소에 ref라는 콜백함수를 props로 전달해주면 됨.
그리고 함수 내부에서 인자로 받은 ref를 컴포넌트의 멤버 변수로 설정해줌.

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

createRef를 통한 ref 설정

리액트에 내장된 createRef 함수 사용
컴포넌트 내부에서 멤버변수에 React.createRef() 로 ref 설정? 해주고, 요소에 ref props로 전달해주면 됨.
콜백함수와 다르게 뒤에 .current 를 붙여줘야함.

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;

컴포넌트에 ref 달기

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

MyComponent 내부의 메서드 및 멤버 변수에도 접근 할 수 있게 된다. 물론 내부 ref에도 접근할 수 있게된다.
버튼 누르면 스크롤바 맨밑으로 가게하는 코드

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

  render() {
    const style = {
      border: "1px solid black",
      height: "300px",
      width: "300px",
      overflow: "auto",
      position: "realative",
    };

    const innerStyle = {
      width: "100%",
      height: "650px",
      background: "linear-gradient(white,black)",
    };
    return (
      <div
        style={style}
        ref={(ref) => {
          this.box = ref;
        }}
      >
        <div style={innerStyle} />
      </div>
    );
  }
}
<button onClick={() => this.scrollBox.scrollToBottom()}>
<button onClick={this.scrollBox.scrollToBottom}>

2번으로 작성할 수도 있지만, 컴포넌트가 처음 렌더링 될때는 this.scrollBox 값이 undefined이므로 scrollToBottom 값을 읽어오는 과정에서 오류가 발생할 수 있음
→ 화살표 함수로 버튼을 누를때 실행되도록.