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

26660 단어 ReactReact

오늘은 ref에 대해서 공부해봅시다!

📖 ref: DOM에 이름 달기

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

❓ 리액트 컴포넌트 안에서 id는 사용하면 안되나?
-id를 사용할 수 있지만 특수한 경우가 아니면 사용을 권장하지는 않는다. 같은 컴포넌트를 여러 번 사용한다면 중복 id를 가진 DOM이 여러개 생기므로 잘못된 사용법이다. (HTML에서 DOM의 id는 유일해야하므로 ! )
✅ 그러나 ref는 전역적으로 작동하지 않고 컴포넌트 내부에서만 작동하기 때문에 문제가 발생하지 않는다 !

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

ref는 DOM을 꼭 직접적으로 건드려야 할 때 사용된다.

ValidationSample 컴포넌트 만들기->input에 ref 달기-> 버튼을 누를 때마다 input에 포커스 주기
순서로 실습을 진행해보자

5.1.1. 예제 컴포넌트 생성

ValidationSample.css와 ValidationSample.js 파일 생성
✍ example

//css
.success {
  background-color: lightgreen;
}

.faliure {
  background-color: lightcoral;
}
//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':'faliure'):''}
                />
                <button onClick={this.handleButtonClick}>검증하기</button>
            </div>
        );
    }
}

export default ValidationSample;
  • input에서는 onChange가 발생하면 handleChange를 호출하여 state의 password값을 업데이트.
  • button에서는 onClick 이벤트가 발생하면 handleButtonClick을 호출하여 clicked값을 true로 설정.
  • input의 clssName 값은 버튼을 누르기 전에는 비어있는 문자열을 전달, 버튼을 누를 후에서는 success 또는 faliure값 전달. (이에 따라 input 색이 변함. )

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

✍ example

//App.js
import { Component } from "react";
import ValidationSample from './ValidationSample';

class App extends Component{
  render() {
    return (
     <ValidationSample/>
    );
  }
}
export default App;

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

  1. 특정 input에 포커스 주기
  2. 스크롤 박스 조작하기
  3. Canvas 요소에 그림그리기

5.2. ref 사용

콜백 함수를 통한 ref 설정createRef를 통한 ref 설정
-가장 기본적인 방법
-ref를 달고자 하는 요소에 ref라는 콜백함수를 props로 전달
-더 적은 코드로 쉽게 사용 가능
-리액트 v16.3부터 도입 (이전 버전에서는 작동하지 않음.)

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

✍ example

<input ref={(ref)=>{this.input=ref}}/>
  • 콜백 함수는 ref 값을 파라미터로 전달 받음.
  • this.input은 input 요소의 DOM을 가리킴. 이를 통해 input이라는 이름의 ref 생성.
  • ref 이름은 자유롭게 설정 가능. ex) this.superman=ref

5.2.2. createRef를 통한 ref 설정

✍ example

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; 
  • 리액트에 내장되어있는 createRef 함수를 이용하여 ref 생성.
    1. input=React.createRef(); : 컴포넌트 내부에서 멤버 변수로 React.createRef()를 담아줌.
    2. input ref={this.input} : ref를 달고자 하는 요소에 ref props로 넣어주면 ref 설정이 완료.
    3. this.input.current.focus(); : ref를 설정한 DOM에 접근하기 위해서는 this.input.current를 조회하면 됨.

5.2.3. 적용

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

5.2.3.1. input에 ref 달기

✍ example

   <input
       ref={(ref)=>this.input=ref}
       (...)
   />
  • 콜백 함수를 이용하여 ref를 달아줌.

5.2.3.2. 버튼 onClick 이벤트 코드 수정

✍ example

handleButtonClick=()=>{
        this.setState({
            clicked:true,
            validated:this.state.password==='0000'
        });
        this.input.focus();
    }
  • this.input이 컴포넌트 내부의 input요소를 가리킴.
  • 따라서 일반 DOM을 다루듯이 코드 작성 가능.

5.3. 컴포넌트에 ref 달기

컴포넌트 내부에 있는 DOM을 컴포넌트 외부에서 사용할 때 컴포넌트에 ref를 단다.

5.3.1. 사용법

✍ example

<MyComponent 
	ref={(ref)=>{this.myComponent=ref}}
/>
  • 컴포넌트에 ref를 달면 MyComponent 내부의 메서드 및 멤버 변수에도 접근 가능.
    ex) myComponent.handleClick, myComponent.input

5.3.2. 컴포넌트 초기 설정

✍ example

//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;
  • ScrollBox.js 컴포넌트 파일 생성. (최상위 DOM에 ref를 달아줌.)

✍ example

//App.js
import { Component } from "react";
import ScrollBox from "./ScrollBox";

class App extends Component{
  render() {
    return (
     <ScrollBox/>
    );
  }
}
export default App;
  • ScrollBox 렌더링.

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

✍ example

    scrollToBottom=()=>{
    const{scrollHeight, clientHeight}=this.box;
    this.box.scrollTop=scrollHeight-clientHeight;
    }
  • scrollTop : 세로 스크롤바 위치
  • scrollHeight : 스크롤이 있는 박스 안의 div 높이
  • clientHeight : 스크롤이 있는 박스의 높이
  • 스크롤바를 맨 아래쪽으로 내리려면 scrollHeight에서 clientHeight 높이를 빼면 됨.

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

✍ example

import { 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이므로 this.scrollBox.scrollBottom값을 읽어오는 과정에서 오류 발생. 따라서 새로운 함수를 만들고 내부에서 this.scrollBox.scrollToBottom 메서드를 실행하면 오류가 발생하지 않음.

✔ 결과 확인


✔ 마치며

컴포넌트 내부에서 DOM에 직접 접근해야 할 때는 ref를 사용한다는 것을 배우고 실습까지 진행해보았습니다. 다음 시간에는 컴포넌트의 반복에 대해서 공부해보겠습니다 🤗

좋은 웹페이지 즐겨찾기