공부 기록

[react] DOM에 이름 달기 ref

by 너나나

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

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

 

DOM 이란

Document Object Model의 약자로 문서 객체 모델이라고 번역할 수 있다. <html>이나 <body>같은 html 문서의 태그들을 javascript가 이용할 수 있는 객체로 만들면 그것을 객체 문서라고 한다. 그러니까 웹 브라우저가 html 페이지를 인식하는 방식을 DOM이라고 하는데 개발자 도구에서 F12를 눌러서 볼 수 있는 친구들이 바로 DOM이다!!

 

src 디렉토리 안에 ValidationSample.css, ValidationSample.js 파일을 만들었다.

ValidationSample.css

.success {
    background-color: lightgreen;
}

.failure {
    background-color: lightcoral;
}
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

비밀번호를 입력하고 확인 버튼을 눌렀을때 비밀번호가 0000이 맞다면 초록색으로 텍스트필드를 바꿔주고 틀렸다면 빨간색으로 바꿔주는 코드이다!!

1234를 입력하고 확인 버튼 누름
0000을 입력했을때

여기서는 state를 사용해서 필요한 기능을 구현했지만, 가끔 state만으로 해결할 수  없는 기능이 있다.

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

이때는 어쩔 수 없이 DOM에 직접적으로 접근해야 하는데, 이를 위해 바로 ref을 사용한다.

 

ref을 만드는 가장 기본적인 방법은 콜백 함수를 사용하는 것이다!! ref를 달고자 하는 요소에 ref라는 콜백 함수를 props로 전달해 주면 된다. 이 콜백 함수는 ref 값을 파라미터로 전달받는다! 그리고 함수 내부에서 파라미터로 받은 ref을 컴포넌트의 멤버 변수로 설정해준다.

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

이렇게 하면 앞으로 this.input은 input 요소의 DOM을 가킨다!! ref의 이름은 원하는 것으로 자유롭게 지정할 수 있다!!

 

리액트에 내장되어있는 createRef 라는 함수를 사용해서 ref을 만들 수도 있다!! 이 함수를 사용해서 만들면 더 적은 코드로 쉽게 사용할 수 있다!!

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 설정이 완료된다. 설정한 뒤 나중에 ref을 설정해 준 DOM에 접근하려면 this.input.current를 조회하면 된다!! 콜백 함수를 사용할 때와 다른점은 뒷부분에 .current를 넣어줘야한다는 것이다!!!

 

그러면 아까 만들었던 ValidationSample 컴포넌트에 ref을 달아보자!!

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'
        })
        this.input.focus();
    }

    render() {
        return (
            <div>
                <input
                    ref={(ref) => this.input=ref}
                    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

버튼을 눌렀을때 다시 input에 커서가 깜박거리게 하기 위해서 handleButtonClick에 this.input.focus();를 추가하고 input에 ref을 달아줬따!!

 

리액트에서는 컴포넌트에도 ref을 달 수 있다. 이 방법은 주로 컴포넌트 내부에 있는 DOM을 컴포넌트 외부에서 사용할 때 쓴다!! 컴포넌트에서 ref를 다는 방법은 DOM에 ref를 다는 방법과 똑같다!!

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

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

 

스크롤 박스가 있는 컴포넌트를 하나 만들고, 스크롤바를 아래로 내리는 작업을 부모 컴포넌트에서 실행해보자!!

ScrollBox라는 컴포넌트 파일을 만들었다!!

import React, { Component } from 'react';

class ScrollBox extends Component {
    render() {
        const style = {
            border: '1px solid balck',
            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>
        )
    }
}

export default ScrollBox;

그리고 App.js로 가서 ScrollBox 컴포넌트를 렌더링해주자!!

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

class App extends Component {
    render() {
        return (
            <div>
                <ScrollBox />
            </div>
        )
    }
}

export default App

그러면 이렇게 스크롤 박스가 잘 렌더링된다!!

 

컴포넌트에 스크로바를 맨 아래쪽으로 내리는 메서드를 만들자!!

자바스크립트로 스크롤바를 내릴 때는 DOM 노드가 가진 다음 값들을 사용한다.

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

스크롤바를 맨 아래쪽으로 내리려면 scrollHeight에서 clientHeight 높이를 빼면 된다.

스크롤바가 저 빨간 만큼 내려와야 하니까 scrollHeight - clientHeight

ScrollBox.js 의 render함수 외부에

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

이 메서드를 추가해줬다!!

이렇게 만든 메서드는 부모 컴포넌트인 App 컴포넌트에서 ScrollBox에 ref를 달면 사용할 수 있다!!

 

그럼 App 컴포넌트에서 ScrollBox에 ref을 달고 버튼을 누르면 ScrollBox 컴포넌트의 scrollToBottom 메서드를 실행하도록 코드를 작성해보자!!

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

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

export default App

이러고 실행해보면

버튼 누르기 전
버튼 누르면

잘 작동하는것을 볼 수 있다!!


참고 자료

 

누구든지 하는 리액트 1편: 리액트는 무엇인가 | VELOPERT.LOG

이 튜토리얼은 10편으로 이뤄진 시리즈입니다. 이전 / 다음 편을 확인하시려면 목차를 확인하세요. 프론트엔드 라이브러리 / 프레임워크 리액트는 정말 인기있는 프론트엔드 라이브러리입니다.

velopert.com

「리액트를 다루는 기술 - 김민준」

'study > react (2021 여름방학)' 카테고리의 다른 글

[react] 라이프사이클 메서드  (0) 2021.07.24
[react] 컴포넌트 반복  (0) 2021.07.18
[react] 이벤트 핸들링  (0) 2021.07.17
[react] props, state  (0) 2021.07.13
[react] 리액트 정리 - 1  (0) 2021.07.11

블로그의 정보

공부 기록

너나나

활동하기