상세 컨텐츠

본문 제목

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

21-22/21-22 리액트 스타터 -2

by dev otcroz 2021. 11. 22. 13:00

본문

728x90

INDEX

5장 ref: DOM에 이름 달기

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

1.1 예제 컴포넌트 생성

1.2 App 컴포넌트에서 예제 컴포넌트 렌더링

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

2. ref 사용

2.1 콜백 함수를 통한 ref 설정

2.2 createRef를 통한 ref 설정

2.3 적용

3. 컴포넌트에 ref 달기

3.1 사용법

3.2 컴포넌트 초기 설정

3.3 컴포넌트에 메서드 생성

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

4. 정리

● 개념 복습 문제

● 코드 문제

 


5장 ref: DOM에 이름 달기

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

→ CSS나 자바스크립트에서 해당 id를 가진 요소를 찾아서 작업할 수 있다.

 

리액트 프로젝트 내부에서 DOM에 이름을 다는 방법을 ref라고 한다.


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

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

id를 사용한 경우

<html>
    <head>
        <meta charset="utf-8">
        <meta name=="viewport" content="width=device-width">
        <title>Example</title>
        <style>
            .success{
                background-color:green;
            }
            .failure{
                background-color: red;
            }
        </style>
        <script>
            function validate(){
                var input =document.getElementById('password');
                input.className='';
                if(input.value==='0000'){
                    input.className='success';
                }else{
                    input.className='failure';
                }
            }
        </script>
    </head>

    <input>
        <input type="password" id="password"></input>
        <button onclick="validate()">validate</button>
    </body>
</html>

 

리액트 컴포넌트에서 state 사용

1. ValidationSample 컴포넌트 만들기

2. input에 ref 달기

3. 버튼을 누를 때마다 input에 포커스 주기

 

 

리액트 컴포넌트에서 state를 사용하여 제시한 기능을 구현해 보겠다.

이 장에서는 클래스형 컴포넌트에서 ref를 사용하는 방법을 알아보겠다.

1.1. 예제 컴포넌트 생성

.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;

input에서 onChange 이벤트가 발생하면 handleChange를 호출해서 state의 password 값을 업데이트 하도록 설정

input의 className 값은 버튼을 누르기 전에는 비어있는 문자열을 전달하고, 버튼을 누른 후에는 검증 결과에 따라서 전달한다.

1.2. App 컴포넌트에서 예제 컴포넌트 렌더링

import React, { Component } from 'react';
import ValidationSample from './ValidationSample';
class App extends Component {
  render() {
    return (
      <ValidationSample/>
    );
  }
}
export default App;

 

App컴포넌트를 함수형 컴포넌트에서 클래스형 컴포넌트로 전환한다.

이는 추후에 ref를 사용할 것이기 때문이다.

 

1.3. DOM을 꼭 사용해야 하는 상황

state만으로 해결할 수 없는 기능을 구현해야 할 때

- 특정 input에 포커스 주기

- 스크롤 박스 조작하기

- Canvas 요소에 그림 그리기 등

 


2. ref 사용(두 가지 방법)

2.1. 콜백 함수를 통한 ref 설정

ref를 달고자 하는 요소에 ref라는 콜백 함수props로 전달해 주면 된다.

이 콜백 함수는 ref 값을 파라미터로 받는다.

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

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

프로젝트 생성 과정에서 node_modules 디렉터리에 react 모듈이 설치된다.

import 구문을 통해 리액트를 불러와서 사용 가능하다.

 

2.2. createRef를 통한 ref 설정

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

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 props로 넣어주면 ref 설정이 완료된다.

 

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

 

2.3. 적용

2.3.1. 적용 -input에 ref 달기

버튼을 한 번 눌렀을 때 포커스가 다시 input쪽으로 자동으로 넘어가도록 코드를 작성한다.

 

- 콜백 함수를 사용해서 ref를 달아보자.

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

 

2.3.2. 적용 -버튼 onClick 이벤트 코드 수정

버튼에서 onClick이벤트가 발생했을 때 input에 포커스를 주도록 코드를 수정

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;

3. 컴포넌트에 ref 달기

3.1. 사용법

주로 컴포넌트 내부에 있는 DOM을 컴포넌트 외부에서 사용할 때 쓰는 방법

컴포넌트에서 ref를 다는 방법은 DOM에 ref를 다는 방법과 똑같다.

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

-위 코드와 같이 하면 MyComponent 내부의 메서드 및 멤버 변수에도 접근할 수 있다.

→ 내부의 ref에도 접근할 수 있다.

 

부모 컴포넌트에서 스크롤바 내리기

1. ScrollBox 컴포넌트 만들기

2. 컴포넌트에 ref 달기

3. ref를 이용하여 컴포넌트 내부 메서드 호출하기

 

3.2. 컴포넌트 초기 설정

먼저 ScrollBox라는 컴포넌트 파일을 만들어 본다.(JSX의 인라인 스타일링 문법으로 스크롤 박스를 만든다)

그 다음 최상위 DOM에 ref를 달아 본다.

3.2.1. 컴포넌트 파일 생성

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>
        );

    }
}

export default ScrollBox;

 

3.2.2. App 컴포넌트에서 스크롤 박스 컴포넌트 렌더링

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

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

export default App;

 

3.3. 컴포넌트에 메서드 생성

- scrollTop: 세로 스크롤바 위치(0~350)

- scrollHeight: 스크롤이 있는 박스 안의 div 높이(650)

- clientHeight: 스크롤이 있는 박스의 높이(300)

import React, { Component } from 'react';

class ScrollBox extends Component {
    scrollBottom=()=>{
        const { scrollHeight, clientHeight }=this.box;
        /*
        const scrollHeight=this.box.scrollHeight;
        const clientHeight=this.box.clientHeight;
        */
       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;

 

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

App 컴포넌트에서 ScrollBox에 ref를 달고 버튼을 만들어 누르면, ScrollBox 컴포넌트의 scrollBottom 메서드를 실행하도록 코드를 작성

import React, { Component } from 'react';

class ScrollBox extends Component {
    scrollToBottom=()=>{
        const { scrollHeight, clientHeight }=this.box;
        /*
        const scrollHeight=this.box.scrollHeight;
        const clientHeight=this.box.clientHeight;
        */
       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;
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;

**주의할 점

onClick={this.scrollBox.scrollBottom}과 같은 형식으로 작성해도 괜찮으나 처음에 this.scrollBox값이 undefined이므로 오류가 발생한다. 그래서 아예 새로운 함수를 이용해서 메서드를 실행해야 한다.


정리 - Quiz 

  개념 복습 문제

1. ref는 (DOM을 직접적으로 건드려야 할 때) 사용한다.

 

2. DOM을 꼭 사용해야 하는 상황은 state만으로 기능을 구현할 수 없을 때이다.  예시로는 (특정 input에 포커스 주기, 스크롤 박스 조작하기, Canvas 요소에 그림 그리기 등)이 있다.

 

3. ref를 사용하는 방법은 두 가지로 (콜백 함수를 통한 ref 설정)과 (createRef를 통한 ref 설정)이 있다.

 

4. 콜백 함수를 통한 ref 설정에서 콜백함수는 ref 값을 (파라미터)로 전달 받는다.

 

5. createRef를 사용하여 ref를 만들 때 해당 멤버 변수를 ref를 달고자 하는 요소에 (ref props)로 넣어주면 ref 설정이 완료된다.

 

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

 

7. onClick={this.scrollBox.scrollBottom}과 같은 형식으로 작성하면 오류가 생기는 이유는 (처음에 this.scrollBox 값이 undefined이기 때문이다).

 

코드 문제

(1) 비구조화 할당 문법을 사용하여 코드를 나타내 보세요.

(2) scrollToTop메서드를 만들고 '맨 위로' 라는 버튼을 추가해 보세요.

import React, { Component } from 'react';

class ScrollBox extends Component {
    scrollToBottom=()=>{
       const scrollHeight=this.box.scrollHeight;
        const clientHeight=this.box.clientHeight;
       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;
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;

Corner React Starter #2

Editor 성민

 

728x90

관련글 더보기