본문 바로가기

react

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

1. ref는 어떤 상황에서 사용해야 할까?

 

- 특정 DOM에 작업을 해야할 때 ref를 사용

 

- DOM을 꼭 사용해야 하는  상황 

  - 특정 input에 포커스 주기

  - 스크롤 박스 조작하기 

  - Canvas 요소에 그림 그리기 

 

ValidationSample.js

import { 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;

- input에서는 onChange 이벤트가 발생하면 handleChange를 호출하여 state의 password 값을 업데이트

- button에서는 onClick 이벤트가 발생하면 handleButtionClick을 호출하여 Clicked값을 참으로 설정하고, validated 값을 검증 결과로 설정 

 

 

2. ref 사용 

 

1) 콜백 함수를 통한 ref 설정 

 

- ref를 달고자 하는 요소에 ref라는 콜백 함수를 props로 전달 

- 콜백 함수는 ref 값을 파라미터로 전달받음

- 함수 내부에서 파라미터로 받은 ref를 컴포넌트의 멤버 변수로 설정

- this.input은 input 요소의 DOM을 가리킴

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

 

2) createRef를 통한 ref 설정 

 

- 리액트에 내장되어 있는 createRef 함수 사용 

- createRef를 사용하여 ref를 만들려면 우선 컴포넌트 내부에서 멤버 변수로 React.createRef()를 담아 주어야 함 

- 해당 멤버 변수로 ref를 달고자 하는 요소에 ref props로 넣어주면 ref 설정이 완료 

- 나중에 ref를 설정해 준 DOM에 접근하려면 this.input.current를 조회

 

import { 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;

 

- ValidationSample.js 코드에서 버튼을 한 번 눌렀을 때, 포커스가 다시 input 쪽으로 자동으로 넘어가도록 수정

 

ValidationSample.js

 

import { 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'
        });
        //onClick 이벤트가 발생했을 떄 input에 포커스 주도록
        this.input.focus();
    }

    render() {
        return (
            <div>
                <input
                    //input에 ref 달기 
                    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;

 

 

 

3. 컴포넌트에 ref 달기 

 

- 컴포넌트 내부에  있는 DOM을 컴포넌트 외부에서 사용할 때

 

1) 사용법 

 

- MyComponent 내부의 메서드 및 멤버 변수에도 접근 가능

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

 

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

 

 

2) 컴포넌트 초기 설정 

 

scrollBox.js

import { 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>
        );
    }
}

export default ScrollBox;

 

 

3) 컴포넌트에 메서드 생성 

 

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

 

  • scrollTop : 세로 스크롤바의 위치
  • scrollHeight : 스크롤이 있는 박스 안의 div 높이 
  • clientHeight : 스크롤이 있는 박스의 높이

 

ScrollBox.js

import React, { Component } from 'react';
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: '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;

 

 

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

 

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

 

App.js

import React, { Component } from 'react';
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;