일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 컬렉션프레임워크
- 객체 비교
- 생성자오버로드
- 컬렉션 타입
- 다형성
- GRANT VIEW
- exception
- 메소드오버로딩
- cursor문
- 사용자예외클래스생성
- oracle
- abstract
- 자바
- NestedFor
- EnhancedFor
- 집합_SET
- 대덕인재개발원
- 자동차수리시스템
- 예외처리
- Java
- 정수형타입
- 환경설정
- 추상메서드
- 어윈 사용법
- 인터페이스
- 오라클
- 한국건설관리시스템
- 제네릭
- 예외미루기
- 참조형변수
- Today
- Total
거니의 velog
(14) ref:DOM 에 이름 달기 2 본문
2. ref 사용
* 이제 프로젝트에서 ref를 사용해 보자. ref를 사용하는 방법은 두 가지이다.
(1) 콜백 함수를 통한 ref 설정
* ref를 만드는 가장 기본적인 방법은 콜백 함수를 사용하는 것이다. ref를 달고자 하는 요소에 ref라는 콜백 함수를 props로 전달해 주면 된다. 이 콜백 함수는 ref 값을 파라미터로 전달받는다. 그리고 함수 내부에서 파라미터로 받은 ref를 컴포넌트의 멤버 변수로 설정해 준다.
* 콜백 함수 사용 예시
<input ref={(ref) => {this.input=ref}} />
* 이렇게 하면 앞으로 this.input은 input 요소의 DOM을 가리킨다. ref의 이름은 원하는 것으로 자유롭게 지정할 수 있다. DOM 타입과 관계없이 this.superman = ref 처럼 마음대로 지정한다.
(2) createRef를 통한 ref 설정
* ref를 만드는 또 다른 방법은 리액트에 내장되어 있는 createRef라는 함수를 사용하는 것이다. 이 함수를 사용해서 만들면 더 적은 코드로 쉽게 사용할 수 있다. 이 기능은 리액트 v16.3부터 도입되었으며, 이전 버전에는 작동하지 않는다.
import React, { Component } from 'react';
class createRef extends Component {
input = React.createRef();
handleFocus = () => {
this.input.current.focus();
};
render() {
return (
<div>
<input ref={this.input} />
</div>
);
}
}
export default createRef;
* createRef 를 사용하여 ref를 만들려면 우선 컴포넌트 내부에서 멤버 변수로 React.createRef()를 담아 주어야 한다. 그리고 해당 멤버 변수를 ref를 달고자 하는 요소에 ref props로 넣어주면 ref 설정이 완료된다.
* 설정한 뒤 나중에는 ref를 설정해 준 DOM에 접근하려면 this.input.current를 조회하면 된다. 콜백 함수를 사용할 때와 다른 점은 이렇게 뒷부분에 .current를 넣어 주어야 한다는 것이다.
* 지금까지 콜백 함수 혹은 createRef를 사용하여 ref를 만드는 방법을 배워 보았다. 앞으로 두 가지 방법 중에서 편한 방법을 사용하자.
* 이번 장에서는 주로 콜백 함수를 사용하는 방식으로 ref를 다루어 보자.
(3) 적용
* 이전에 만든 ValidationSample 컴포넌트의 렌더링 결과를 다시 한 번 살펴 보자.
* input 요소를 클릭하면 포커스가 되면 텍스트 커서가 깜박인다.
* 버튼을 누르면 포커스가 버튼으로 넘어가면서 왼쪽 input 요소의 텍스트 커서가 더 이상 보이지 않는다.
* 버튼을 한 번 눌렀을 때, 포커스가 다시 input쪽으로 자동으로 넘어가도록 코드를 작성해 보자.
[1] input에 ref 달기
* 이전에 배운 대로 콜백 함수를 사용하여 ValidationSample 컴포넌트에도 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>
);
}
[2] 버튼 onClick 이벤트 코드 수정
* 버튼에서 onClick 이벤트가 발생할 때 input에 포커스를 주도록 코드를 수정해 보자. 이제 this.input이 컴포넌트 내부의 input 요소를 가리키고 있으나, 일반 DOM을 다루듯이 코드를 작성하면 된다.
handleButtonClick = () => {
this.setState({
clicked: true,
validated: this.state.password === '0000',
});
this.input.focus();
};
* 코드를 저장하고, 웹 브라우저에서 페이지를 열어 버튼을 눌러 보자. 포커스가 input으로 바로 넘어간다.
3. 컴포넌트 ref 달기
* 리액트에서는 컴포넌트에서 ref를 달 수 있다. 이 방법은 주로 컴포넌트 내부에 있는 DOM을 컴포넌트 외부에서 사용할 때 쓴다. 컴포넌트에서 ref를 다는 방법은 DOM에 ref를 다는 방법과 똑같다.
(1) 사용법
<MyComponent
ref={(ref) => (this.myComponent=ref)}
/>
* 이렇게 하면 MyComponent 내부의 메서드 및 멤버 변수에도 접근할 수 있다. 즉, 내부의 ref에도 접근할 수 있다(예: myComponent, handleClick, myComponent.input 등).
* 이번에는 스크롤 박스가 있는 컴포넌트를 하나 만들고, 스크롤바를 아래로 내리는 작업을 부모 컴포넌트에서 실행해 보자.
* 이번 실습은 다음 흐름으로 진행한다.
(2) 컴포넌트 초기 설정
* 먼저 ScrollBox 라는 컴포넌트 파일을 만들자. JSX 인라인 스타일링 문법으로 스크롤 박스를 만들어 보자. 그 다음에는 최상위 DOM에 ref를 달아주자.
[1] 컴포넌트 파일 생성
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>
</div>
);
}
}
export default ScrollBox;
[2] App 컴포넌트에서 스크롤 박스 컴포넌트 렌더링
* 기존 ValidationSample을 지우고, 방금 만든 ScrollBox 컴포넌트를 렌더링 하자.
import React, { Component } from 'react';
import ScrollBox from './ScrollBox';
class App extends Component {
render() {
return (
<div>
<ScrollBox />
</div>
);
}
}
export default App;
* 코드를 저장하고, 웹 브라우저에서 스크롤 박스가 잘 렌더링되어 있는지 확인해 보자.
[3] 컴포넌트에 메서드 생성
* 컴포넌트에 스크롤바를 맨 아래쪽으로 내리는 메서드를 만들어 보자. 자바스크립트로 스크롤바를 내릴 때는 DOM 노드가 가진 다음 값들을 사용한다.
- scrollTop : 세로 스크롤바 위치(0~350)
- scrollHeight : 스크롤이 있는 박스 안의 div 높이(650)
- clientHeight : 스크롤이 있는 박스의 높이(300)
* 스크롤바를 맨 아래쪽으로 내리려면 scrollHeight에서 clientHeight 높이를 빼면 된다.
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() { ... }
}
export default ScrollBox;
* scrollToBottom 메서드의 첫 번째 줄에서는 ES6의 비구조화 할당 문법을 사용했다.
* 이렇게 만든 메서드는 부모 컴포넌트인 App 컴포넌트에서 ScrollBox에 ref를 달면 사용할 수 있다.
[4] 컴포넌트에 ref 달고 내부 메서드 사용
* 그럼 App 컴포넌트에서 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;
* 여기서 주의할 점이 하나 있다. 문법상으로는 onClick = {this.scrollBox.scrollToBottom} 같은 형식으로 작성해도 틀린 것은 아니다. 하지만 컴포넌트가 처음 렌더링될 때는 this.scrollBox 값이 undefined이므로 this.scrollBox.scrollToBottom 값을 읽어 오는 과정에서 오류가 발생한다. 화살표 함수 문법을 사용하여 아예 새로운 함수를 만들고 그 내부에서 this.scrollBox.scrollToBottom 메서드를 실행하면, 버튼을 누를 때(이미 한 번 렌더링을 해서 this.scrollBox를 설정한 시점) this.scrollBox.scrollToBottom 값을 읽어 와서 실행하므로 오류가 발생하지 않는다.
* 자, 이제 코드를 지정하고 웹 브라우저에서 맨 밑으로 버튼을 눌러보자.
4. 정리
* 컴포넌트 내부에 DOM을 직접 접근해야 할 때는 ref를 사용한다. 먼저 ref를 사용하지 않고도 원하는 기능을 구현할 수 있는지 반드시 고려한 후에 활용해야 한다.
* 이 시점에서 오해할 수 있는 부분은, 서로 다른 컴포넌트끼리 데이터를 교류할 때 ref를 사용한다면 이는 잘못된 사용법이다. 물론 할수는 있으나, 컴포넌트에 ref를 달고 그 ref를 다른 컴포넌트로 전달하고 ...... 다른 컴포넌트에서 ref 로 전달 받은 컴포넌트의 메서드를 실행하고 ...... 하지만 이 방법은 리액트 사상에 어긋난 설계이다. 앱 규모가 커지면 마치 스파게티처럼 구조가 꼬여 버려서 유지 보수가 불가능하게 된다. 컴포넌트끼리 데이터를 교류할 때는 언제나 데이터를 부모 <-> 자식 흐름으로 교류해야 한다. 나중에 리덕스 혹은 Context API를 사용하여 효율적으로 교류하는 방법을 배울 것이다.
* 아직 함수형 컴포넌트에서 ref를 사용하는 것은 배우지 않았는데, 함수형 컴포넌트에서 useRef라는 Hook 함수를 사용한다. 사용법은 이 장에서 배운 React.createRef와 유사하다. 이에 관련된 내용은 추후에 알아보도록 하자.
'React_리액트 시작' 카테고리의 다른 글
(16) 컴포넌트 반복 2 (1) | 2023.12.01 |
---|---|
(15) 컴포넌트 반복 1 (0) | 2023.12.01 |
(13) ref:DOM 에 이름 달기 1 (0) | 2023.11.30 |
(12) 이벤트 핸들링 2 (0) | 2023.11.30 |
(11) 이벤트 핸들링 1 (2) | 2023.11.30 |