HTML에서 특정 요소에 접근하려면 어떻게 해야할까?
<div id='my-element'> <div>
이런식으로 div요소에 id값을 달아줘서 이후에 css나 자바스크립트에서 id값을 이용해서 div 요소에 접근, 작업을 진행할 수 있다
리액트 프로젝트 내부에서도 이런식으로 DOM에 이름을 다는 방법이 있는데 바로 ref(reference)다
5-1. ref 사용하기
ref는 어떤 상황에서 사용해야할까?
- 구현하려는 기능이 state만으로는 해결할 수 없을 때
- 포커스, 텍스트 선택영역, 혹은 미디어의 재생을 관리할 때
- 애니메이션을 직접적으로 실행시킬 때
'모두 DOM을 직접적으로 건드려야 할 때' 로 귀결된다
예제 코드
import React, { Component } from 'react';
import './ValidationSample.css';
// in ValidationSample.css
.success {
background-color: lightgreen;
}
.failure {
background-color: lightcoral;
}
// ValidationSample
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박스에 비밀번호를 입력한 뒤 검증하기 버튼을 클릭했을 때
0000이면 input 박스를 초록색으로 그렇지 않다면 빨간색으로 바꾼다
여기서 input박스를 칠하는 기능에 ref를 쓰지않은 이유는 보는 바와 같이 클릭에 따라 className을 바꿔주는 기능만 구현하면 DOM을 직접적으로 건드릴 필요가 없기 때문이다
이제 ref가 필요한 상황인 포커스 이동을
5-1-1. 콜백 함수를 통한 ref 설정
ref를 만드는 가장 기본적인 방법은 콜백 함수를 사용하는 것이다
ref를 달고자 하는 요소에 ref 파라미터를 가진 콜백 함수를 props로 전달해 주고 함수 내부에서 ref를 컴포넌트의 멤버 변수로 설정해 주면 된다
밑의 예를 보자
render() {
return (
<div>
<input
**ref={(ref) => this.input=ref}
...
...**
/>
처럼 input 요소 안에 콜백함수로 ref를 달아주면 이후에 this.input이 컴포넌트 내부의 input을 가르키고 있게 되니 일반 DOM을 다루듯 코드를 작성하면 된다
이제 검증하기 버튼을 눌렀을 때 포커스가 버튼이 아닌 input박스로 옮겨가도록 handleButtonClick이벤트의 코드를 수정해보자
handleButtonClick = () => {
this.setState({
clicked: true,
validated: this.state.password === '0000'
});
this.input.focus();
};
5-1-2. createRef를 통한 ref 설정
ref를 만드는 또 다른 방법인 내장 함수 createRef를 사용해서 위와 같이 포커스 관리를 구현해보자
class ValidationSample extends Component {
input = React.createRef();
...
...
createRef을 사용하기 위해서는 우선 컴포넌트 내부에 변수를 선언해서 함수를 담아주어야 한다
그 후 ref를 담을 요소에 가서
render() {
return (
<div>
<input
ref={this.input}
type="password"
...
...
해당 요소의 props로 넣어주면 설정이 완료된다
하지만 위에서 설정한 콜백 함수와는 살짝 다르게 이상태의 this.input은 바로 input을 가르키는게 아닌
와 같이 input을 포함하고 있는 객체다 따라서 위와 같이 접근해선 위해선 this.input.currnet로 작성해야한다
handleButtonClick = () => {
this.setState({
clicked: true,
validated: this.state.password === '0000'
});
this.input.current.focus();
};
5-2. 컴포넌트에 ref 달기
DOM 요소가 아닌 컴포넌트 자체에도 ref를 달 수가 있다
주로 컴포넌트 내부에 있는 DOM을 외부 컴포넌트에서 접근하기 위해서 달아주는데 방법은 다르지 않다
<MyComponent ref={ref=> this.MyComponent = ref} />
5-2-1. 예제 코드
컴포넌트 내부의 DOM을 외부 컴포넌트에서..? 이게 대체 무슨 소릴까 싶지만 이런 예시를 보면 쉽다
// in App.js
import ScrollBox from './ScrollBox';
class App extends Component {
render() {
return (
<div>
<ScrollBox/>
</div>
);
}
}
export default App;
//in ScrollBox.js
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}>
<div style={innerStyle}/>
</div>
);
}
}
export default ScrollBox;
아래와 같은 모양이 나온다
아래로 갈수록 검정색으로 그라데이션되는 스크롤박스를 가진 ScrollBox 컴포넌트가 있고
이 ScrollBox 컴포넌트 렌더링하는 상위 App컴포넌트가 존재한다
여기서 우리는 App컴포넌트에 맨 밑으로 라는 버튼을 달고 그 버튼을 누르면 스크롤이 아래로 가도록 구현해보자
//in App.js
render() {
return (
<div>
<ScrollBox/>
<button> 맨 밑으로 </button>
</div>
);
}
우선 App에 버튼이 있어야 할 것 같은데.. App에서 ScrollBox 내부에 있는 박스에 접근해야하는데 방법이 없다
하지만 우리는 컴포넌트에 ref를 달아주면 컴포넌트 내부의 DOM에도 접근할 수 있는 것을 알고있다
//in App.js
render() {
return (
<div>
<ScrollBox ref={(ref)=>this.scrollBox=ref}/>
<button> 맨 밑으로 </button>
</div>
);
}
이제 ScrollBox접근은 할 수 있지만 실제 박스는 아직 건드릴 수 없다
외부에서 박스를 조작하기 위해 컴포넌트 내부의 박스에도 ref를 설정해주자
//in ScrollBox.js
return (
<div style={style}
ref={(ref)=>this.box=ref}
>
<div style={innerStyle}/>
</div>
);
설정을 해 주고 나니 외부에서 박스를 직접 건드릴 필요는 없을 것 같다..
내부에서 박스의 스크롤을 이동시키는 함수를 만들고, 그 함수를 외부에서 실행시키는 것으로 충분해 보인다
//in ScrollBox.js
class ScrollBox extends Component {
scrollToBottom=()=>{
const {scrollHeight, clientHeight} = this.box;
this.box.scrollTop = scrollHeight-clientHeight;
}
함수를 대충 설명하면 박스 전체의 높이와 볼 수 있는 박스의 높이를 뺀 값을 현재 스크롤 위치로 이동시키는...
그러한 함수다
이제 스크롤을 조작하는 함수를 작성했으니 외부에서 함수를 실행시키기만 하면 된다
render() {
return (
<div>
<ScrollBox ref={ref=>this.scrollBox=ref}/>
<button onClick={this.handleClick}> 맨 밑으로 </button>
</div>
);
}
handleClick =()=>{
this.scrollBox.scrollToBottom();
}
버튼을 누르면 스크롤이 밑으로 내려간다!
'React > 리액트를 다루는 기술' 카테고리의 다른 글
7. 라이프사이클 메서드 (0) | 2021.01.20 |
---|---|
6. 컴포넌트 반복 (0) | 2021.01.17 |
4. 이벤트 핸들링 (0) | 2021.01.12 |
3. 컴포넌트 (0) | 2021.01.09 |
2. JSX (0) | 2021.01.08 |