일반적인 HTML에서 DOM 요소에 이름을 달 때는 id를 이용한다.
→ CSS나 자바스크립트에서 해당 id를 가진 요소를 찾아서 작업할 수 있다.
리액트 프로젝트 내부에서 DOM에 이름을 다는 방법을 ref라고 한다.
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>
1. ValidationSample 컴포넌트 만들기
2. input에 ref 달기
3. 버튼을 누를 때마다 input에 포커스 주기
리액트 컴포넌트에서 state를 사용하여 제시한 기능을 구현해 보겠다.
이 장에서는 클래스형 컴포넌트에서 ref를 사용하는 방법을 알아보겠다.
.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 값은 버튼을 누르기 전에는 비어있는 문자열을 전달하고, 버튼을 누른 후에는 검증 결과에 따라서 전달한다.
import React, { Component } from 'react';
import ValidationSample from './ValidationSample';
class App extends Component {
render() {
return (
<ValidationSample/>
);
}
}
export default App;
App컴포넌트를 함수형 컴포넌트에서 클래스형 컴포넌트로 전환한다.
이는 추후에 ref를 사용할 것이기 때문이다.
state만으로 해결할 수 없는 기능을 구현해야 할 때
- 특정 input에 포커스 주기
- 스크롤 박스 조작하기
- Canvas 요소에 그림 그리기 등
ref를 달고자 하는 요소에 ref라는 콜백 함수를 props로 전달해 주면 된다.
이 콜백 함수는 ref 값을 파라미터로 받는다.
함수 내부에서 파라미터로 받은 ref를 컴포넌트의 멤버 변수로 설정한다.
<input ref={(ref)=>{this.input=ref}} />
프로젝트 생성 과정에서 node_modules 디렉터리에 react 모듈이 설치된다.
import 구문을 통해 리액트를 불러와서 사용 가능하다.
리액트에 내장되어 있는 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를 조회하면 된다.
버튼을 한 번 눌렀을 때 포커스가 다시 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>
);
}
}
버튼에서 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;
주로 컴포넌트 내부에 있는 DOM을 컴포넌트 외부에서 사용할 때 쓰는 방법
컴포넌트에서 ref를 다는 방법은 DOM에 ref를 다는 방법과 똑같다.
<MyComponent
ref={(ref)=>{this.myComponent=ref}}
/>
-위 코드와 같이 하면 MyComponent 내부의 메서드 및 멤버 변수에도 접근할 수 있다.
→ 내부의 ref에도 접근할 수 있다.
1. ScrollBox 컴포넌트 만들기
2. 컴포넌트에 ref 달기
3. ref를 이용하여 컴포넌트 내부 메서드 호출하기
먼저 ScrollBox라는 컴포넌트 파일을 만들어 본다.(JSX의 인라인 스타일링 문법으로 스크롤 박스를 만든다)
그 다음 최상위 DOM에 ref를 달아 본다.
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;
import React, { Component } from 'react';
import ScrollBox from './ScrollBox';
class App extends Component {
render() {
return (
<div>
<ScrollBox/>
</div>
);
}
}
export default App;
- 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;
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이므로 오류가 발생한다. 그래서 아예 새로운 함수를 이용해서 메서드를 실행해야 한다.
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 성민
<리액트를 다루는 기술> 7장: 컴포넌트의 라이프사이클 메서드 (0) | 2021.12.27 |
---|---|
<리액트를 다루는 기술> 6장: 컴포넌트 반복 (0) | 2021.11.29 |
<리액트를 다루는 기술> 4장: 이벤트 핸들링 (0) | 2021.11.15 |
<리액트를 다루는 기술> 3장: 컴포넌트 (0) | 2021.11.08 |
<리액트를 다루는 기술> 2장: JSX (0) | 2021.11.01 |