[React]ref:DOM에 이름달기
이 글은 [리액트를 다루는 기술](저자 김민준, 출판사 길벗) 교재를 보고 공부하며 정리한 글임.
html 에서 id를 사용하여 DOM에 이름을 다는 것처럼
리액트 프로젝트 내부에서 DOM에 이름을 다는 방법 -> ref
DOM이 뭐더라?
Document Object Model의 약어
객체로 문서 구조를 표현하는 방법
ref는 언제 사용해야할까? -> DOM을 직접적으로 건드려야 할때
함수형 컴포넌트에서 ref를 사용하려면 Hooks를 사용해야 함(뒤에서 나옴)
예제 컴포넌트
ValidationSample.css
.success{
background-color: lightgreen;
}
.failure{
background-color: lightcoral;
}
ValidationSample.js
import { findAllByTestId } from '@testing-library/react';
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;
App.js
import React, {Component} from 'react';
import ValidationSample from './ValidationSample';
class App extends Component{
render(){
return(
<ValidationSample/>
);
}
}
export default App;
0000 을 입력했을때
그런데 이렇게 state 를 사용하는 걸로는
특정 input에 포커스주기
스크롤 박스 조작하기
Canvas 요소에 그림그리기 등
해결할 수 없는 기능들이 있다
따라서 이럴땐 DOM을 직접적으로 접근해야하고 이럴때 ref를 사용
ref 사용 방법은 2가지
1. 콜백함수를 통한 ref 설정
예시
<input ref={(ref) -> {this.input=ref}} />
2. createRef 를 통한 ref 설정
리액트에 내장되어 있는 createRef라는 함수를 사용하기
input에 ref 달기
<input
ref={(ref) => this.input=ref}
//...
버튼 onClick 이벤트 발생하면 input에 포커스를 주도록 수정하기
컴포넌트에 ref 달기
<Mycomponent
ref={(ref) => {this.myComponent=ref}}
/>
이렇게 하면 MyComponent의 메서드와 멤버변수에 접근가능
ScrollBox 컴포넌트 만들기
ScrollBox.js
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 = {
widht:'100%',
height:'650px',
background:'linear-gradient(white, black)'
}
return(
<div
style={style}
ref={(ref) => {this.box = ref}}>
<div style={innerStyle}/>
</div>
);
}
}
export default ScrollBox;
기존 ValidationSample 지우고
방금 만든 컴포넌트 렌더링 하기
App.js
import React, {Component} from 'react';
import ScrollBox from './ScrollBox';
class App extends Component{
render(){
return(
<div>
<ScrollBox/>
</div>
);
}
}
export default App;
잘 렌더링 되었다
ScrollBox.js
import React, {Component} from 'react';
class ScrollBox extends Component {
//비구조화 할당 문법
scrollToBottom=()=>{
const{scrollHeight, clientHeight}=this.box;
this.box.scrollTop = scrollHegiht - clientHeight;
}
render(){
const style={
border:'1px solid black',
height:'300px',
width:'300px',
overflow:'auto',
position:'relative'
};
const innerStyle = {
widht:'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를 달면 사용할 수 있음
App.js
여기에 ScrollBox에 ref를 달고 버튼을 만들어 누르면 ScrollBox의 scrollToBottom 실행
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;