[리액트공부] 5. ref

kkado·2022년 7월 30일
0

리다기

목록 보기
6/16
post-thumbnail

ref ?

일반적인 HTML에서 DOM 요소에 이름을 달 때는 id를 사용한다.

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

이렇듯, 리액트 프로젝트 내부에서 DOM에 이름을 다는 방법이 바로 ref(reference)이다.

리액트 컴포넌트에서 id를 사용하면 안될까? 사용할 수는 있지만 특수한 경우가 아니면 권장되지 않는 방법이다. HTML에서 DOM의 id는 유일해야 하는데, 리액트에서는 같은 컴포넌트를 여러 번 사용할 수 있다보니 중복된 id를 가진 DOM이 여러 개 생길 수 있다.

ref를 사용하는 상황

DOM을 반드시 직접적으로 건드려야 할 때 ref를 사용한다.

예시 코드

ValidationSample.js

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

export default class ValidationSample extends Component {
    state = {
        password: '',
        clicked: false,
        validated: false
    }
  
    handleChange = (e) => {
        this.setState({
            password: e.target.value
        });
    }

    handleButtonClick = (e) => {
        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') : null}
        />
        <button onClick={this.handleButtonClick}>Validate</button>
      </div>
    )
  }
}

ValidationSample.css

.success {
    background-color: lightgreen;
}

.failure {
    background-color: lightcoral;
}

ref 사용

콜백(callback) 함수를 통한 ref 설정

ref를 만드는 가장 기본적 방법은 콜백 함수를 사용하는 것이다.
ref을 달고자 하는 요소에 ref라는 콜백 함수를 props로 전달해 주면 된다.

콜백 함수는 ref 값을 파라미터로 전달 받는다.
그리고 함수 내부에서 파라미터로 받은 ref을 컴포넌트의 멤버 변수에 선언해 준다.

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

createRef를 통한 ref 설정

또 하나의 방법은 리액트에 내장되어 있는 createRef 함수를 사용한다. (리액트 v16.3 버전부터 도입되었으며, 그보다 이전 버전에서는 작동하지 않는다)

export default class RefSample extends Component {
  input = React.createRef();

  handleFocus = () => {
    this.input.current.focus();
  }

  render() {
    return (
      <div>
        <input ref={this.input} />
      </div>
    );
  }
}

createRef를 이용하려면 컴포넌트 내부에서 멤버 변수로 React.createRef()를 담아 주어야 한다. 그리고 ref props로 요소에 해당 변수를 넣어주면 된다.

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

ref 사용

위의 예시 코드 ValidationSample 코드를 다시 가져와서, 실행해보면

Validate 버튼을 누르면, input 입력창에 포커스가 풀려서 입력할 수 없게 된다.

이제 콜백 함수를 이용해서 input에 ref를 달아 보자.

		<input
          ref={(ref) => (this.input = ref)}
          type="password"
          value={this.state.password}
          onChange={this.handleChange}
          className={
            this.state.clicked
              ? this.state.validated
                ? "success"
                : "failure"
              : ""
          }
        />

이제 this.input이 컴포넌트 내부의 input을 가리키고 있다.

그리고 buttonClick 함수를 수정해 준다.

handleButtonClick = (e) => {
    this.setState({
      clicked: true,
      validated: this.state.password === "0000",
    });
    this.input.focus();
  };

focus를 this.input에게 주어서 다시 바로 입력할 수 있게끔 해 준다.

컴포넌트에 ref 달기

컴포넌트에 ref 다는 방법도 DOM에 ref 다는 방법과 똑같다.

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

이렇게 하면 MyComponent 내부의 메서드 및 멤버 변수에 접근할 수 있다.

즉 내부의 ref에도 접근할 수 있다. (myComponent.handleClick 등등)

예시 코드

ScrollBox.js

export default class RefSample extends Component {
  input = React.createRef();

  handleFocus = () => {
    this.input.current.focus();
  }

  render() {
    return (
      <div>
        <input ref={this.input} />
      </div>
    );
  }
}


스크롤 박스가 생성 되었다.

컴포넌트에 스크롤바를 맨 아래쪽으로 내리는 메서드를 만들 것이다.
자바스크립트에서 스크롤바를 내릴 때는 DOM 노드의 다음 값들을 사용한다.

  • scrollTop: 세로 스크롤바 위치(0~350)
  • scrollHeight: 스크롤이 있는 박스 안의 div 높이(650)
  • clientHeight: 스크롤이 있는 박스의 높이(300)

스크롤바를 맨 아래로 내리려면 scrollHeight - clientHeight를 하면 될 것이다.

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

ScrollBox.js

  scrollToBottom = () => {
    const { scrollHeight, clientHeight } = this.box;
    this.box.scrollTop = scrollHeight - clientHeight;
  };

다음과 같은 함수를 구현해 준 뒤에 App.js에서

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

ScrollBox에 ref를 달고 버튼을 만들어 누르면 ScrollBox 컴포넌트 안의 scrollToBottom 메서드를 실행할 수 있다.

여기서 주의할 점이 App.js의 button onClick 함수인데, 그냥 onClick={this.scrollBox.scrollToBottom}이라고 작성해도 틀린 것은 아니다.

하지만 컴포넌트가 처음 렌더링될 때는 this.scrollBoxundifined 이므로 this.scrollBox.scrollToBottom 값을 읽어오는 데 오류가 발생한다.

그래서 화살표 함수를 사용하여 새로운 함수를 만들고, 그 내부에서 this.scrollBox.scrollToBottom 함수를 호출하는 방식으로 실행하면, 버튼을 누를 때 값을 읽어 와서 실행하므로 오류가 발생하지 않는다.

profile
울면안돼 쫄면안돼 냉면됩니다

0개의 댓글