안녕하세요, 코린이의 코딩 학습기 채니 입니다.
[리액트를 다루는 기술]의 책을 참고하여 포스팅한 개인 공부 내용입니다.
일반 HTML에서 DOM 요소에 이름을 달 때는 id를 사용하지만, 리액트에서는 ref를 사용합니다.
※ 리액트에서 id값이 아닌 ref를 사용하는 이유는?
- 같은 컴포넌트를 여러 번 사용한다고 할 때, id는 유일해야 하는데, 중복 id를 가진 DOM이 여러 개 생길 수 있으니, 문제 발생 원인이 될 수 있음!
ref: DOM에 이름 달기
ref를 사용해야 하는 상황
DOM를 직접적으로 건드려야 할 때 ref를 사용합니다.
예를 들어,
javascript 혹은 jQuery로 만든 웹 사이트는 특정 input 요소를 찾을 때 해당 id값을 가진 input에 클래스를 설정해주곤 합니다.
javascript 이용 코드 - 비밀번호 입력 후 버튼 클릭 시 0000일 땐 초록바탕 / 이 외에는 빨간바탕 렌더링
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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>
<body>
<input type="password" id="password" />
<button onclick="validate()">validate</button>
</body>
</html>
하지만 해당 기능을 리액트에서는 위와 같이 DOM에 접근하지 않아도 state로 구현할 수 있습니다.
state를 통해 기능 구현
예제 컴포넌트 생성
ValidationSample.css
.success {
background-color: lightgreen;
}
.failure {
background-color: lightcoral;
}
ValidationSample.js
import { Component } from "react";
import './ValidationSample.css';
class ValidationSample extends Component {
state = {
password: '',
clicked: false,
validate: false
}
handleChange = (e) => {
this.setState({
password: e.target.value
});
}
handleButtonClick = () => {
this.setState({
clicked: true,
validate: this.state.password === '0000'
});
}
render() {
return (
<div>
<input
type="password"
value={this.state.password}
onChange={this.handleChange}
className={this.state.clicked ? (this.state.validate ? 'success' : 'failure') : ''}
/>
<button onClick={this.handleButtonClick}>검증하기</button>
</div>
);
}
}
export default ValidationSample
input에서 onChange 이벤트 발생 시 state의 password 값을 현재 입력 값으로 업데이트 해주고,
button에서 onClick 이벤트 발생 시 clicked를 참으로 변경 / validate 값을 검증 결과로 변경해주었습니다.
input의 className은 값을 누르기 전엔 비어있는 문자열로, 누른 후엔 검증 결과에 따라 'success' 혹은 'failure'로 설정해주었습니다.
App 컴포넌트에서 예제 컴포넌트 렌더링
App.js
import { Component } from 'react';
import './App.css'
import ValidationSample from './ValidationSample';
class App extends Component {
render() {
return (
<ValidationSample/>
)
}
}
export default App;
입력 값에 따라 결과물이 제대로 반영 되는 것을 확인할 수 있습니다.
DOM을 꼭 사용해야 하는 상황은?
위 예제에선 state를 통해 기능 구현을 했지만, state만으로 해결 불가한 기능들이 있습니다.
- 특정 input에 포커스 주기
- 스크롤 박스 조작하기
- Canvas 요소에 그림 그리기 등
이러한 상황 등에는 DOM에 직접 접근해야 하며, 이 때는 ref를 사용합니다.
ref 사용
방법 ① 콜백 함수를 통한 ref 설정
ref를 달고자 하는 요소에 ref라는 콜백 함수를 props로 전달해 줍니다.
<input ref={(ref) => {this.input = ref}}/>
해당 콜백 함수는 ref 값을 파라미터로 전달 받고, 함수 내부에서 전달 받은 ref를 컴포넌트의 멤버 변수로 설정해줍니다.
따라서, this.input은 input 요소의 DOM을 가리키게 되며 이 때 이름은 this.superman = ref 같이 맘대로 정할 수 있습니다.
방법 ② 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;
createRef를 사용하여 ref 생성 시,
① 컴포넌트 내부에서 멤버 변수로 React.createRef()를 담아주어야 합니다. (input = React.createRef)
② 해당 멤버 변수를 ref를 달고자 하는 요소에 ref props로 넣어주면 설정이 완료 됩니다.
추후 ref를 설정한 DOM에 접근하려면 this.input.current를 조회해주면 됩니다.
그렇다면 ref를 이용해 이전에 만들었던 ValidationSample의 코드 중 버튼 클릭 시,
포커스를 input으로 넘어가도록 코드를 작성해보겠습니다.
input에 ref 달기
ValidationSample.js - render() 함수
render() {
return (
<div>
<input
ref={(ref) => {this.input = ref}} // ref 설정
type="password"
value={this.state.password}
onChange={this.handleChange}
className={this.state.clicked ? (this.state.validate ? 'success' : 'failure') : ''}
/>
<button onClick={this.handleButtonClick}>검증하기</button>
</div>
);
}
버튼 onClick 이벤트 코드 수정
ValidationSample.js - handleButtonClick 메소드
handleButtonClick = () => {
this.setState({
clicked: true,
validate: this.state.password === '0000'
});
this.input.focus();
}
this.input이 컴포넌트 내부의 input을 가리키게 되어 일반 DOM을 다루듯이 코드를 작성해 기능을 구현하였습니다.
'검증하기' 버튼을 클릭하면 포커스가 input박스로 넘어가는 것을 확인할 수 있습니다.
createRef()를 이용해서도 위와 같은 기능을 구현해낼 수 있죠.
class ValidationSample extends Component {
input = React.createRef();
state = {
password: '',
clicked: false,
validate: false
}
handleChange = (e) => {
this.setState({
password: e.target.value
});
}
handleButtonClick = () => {
this.setState({
clicked: true,
validate: this.state.password === '0000'
});
console.log(this.input.current);
this.input.current.focus();
}
render() {
return (
<div>
<input
ref={this.input} // ref 설정
type="password"
value={this.state.password}
onChange={this.handleChange}
className={this.state.clicked ? (this.state.validate ? 'success' : 'failure') : ''}
/>
<button onClick={this.handleButtonClick}>검증하기</button>
</div>
);
}
}
콜백 함수 이용과 달리 this.input.current로 해당 DOM을 찾아오는 것을 확인할 수 있습니다.
'JavaScript > React' 카테고리의 다른 글
React) 컴포넌트 반복 (map, filter, key) (0) | 2022.11.14 |
---|---|
React) ref - 컴포넌트에 이름 달기 (0) | 2022.11.11 |
React) 이벤트 핸들링 (클래스형 컴포넌트, 함수형 컴포넌트) (0) | 2022.11.10 |
React) state에 대해서 (클래스형 컴포넌트의 setState, 함수형 컴포넌트의 useState) (0) | 2022.11.01 |
React) props에 대해서 (0) | 2022.11.01 |