You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

151 lines
8.0 KiB

---
id: more-about-refs-ko-KR
title: refs 심화
permalink: more-about-refs-ko-KR.html
prev: working-with-the-browser-ko-KR.html
next: tooling-integration-ko-KR.html
---
render 메소드를 통해 UI 구조를 얻은 다음, 반환된 컴포넌트 인스턴스에 접근하거나 메소드를 호출할 방법이 필요할 수도 있습니다. 반응 적 데이터 플로우가 `render()`의 결과물에서 최신의 `props`가 각각의 자식으로 보내진 것을 항상 보장하기 때문에 어플리케이션의 데이터 플로우를 만드는데 대체로 이런 작업은 필요가 없지만, 여전히 이런 작업이 필요하거나 유리한 경우가 있긴 합니다.
인스턴스의 하위 계층구조에 존재하는 `<input />` 엘리먼트의 value를 빈 문자열(`''`)로 업데이트한 후 포커스 하는 경우를 생각해 봅시다.
```javascript
var App = React.createClass({
getInitialState: function() {
return {userInput: ''};
},
handleChange: function(e) {
this.setState({userInput: e.target.value});
},
clearAndFocusInput: function() {
this.setState({userInput: ''}); // 입력내용을 지워줍니다
// 이제 <input />에 포커스를 주길 원합니다!
},
render: function() {
return (
<div>
<div onClick={this.clearAndFocusInput}>
클릭해서 초기화하고 포커스주기
</div>
<input
value={this.state.userInput}
onChange={this.handleChange}
/>
</div>
);
}
});
```
한번 살펴보죠. 이 예제에서 우리는 시간이 지남에 따라 props에서 추론할 수 없는 무언가를 입력하도록 "알려주길" 원했습니다. 이 사례에서 우리는 이제 포커스 되도록 "알려주길" 원합니다. 그러나 몇 가지 문제가 있습니다. `render()`에서 반환된 것은 "자식" 컴포넌트의 실제 구성이 아니고, 단지 특정 시점의 인스턴스의 자식에 대한 *서술*일 뿐입니다. - 말하자면 스냅 샷인 것이지요.
> 주의:
>
> 기억하세요, `render()`에서 반환된 것은 *실제* 자식 인스턴스가 아닙니다. 단지 특정 시점의 컴포넌트의 하위 계층구조에 있는 자식 인스턴스의 *서술*일 뿐입니다.
이는 `render()`에서 반환된 무언가를 "계속 유지할 수" 없으며 아무런 의미도 없을 것이라는 뜻입니다.
```javascript
// 반례: 이렇게 하면 안됩니다!
render: function() {
var myInput = <input />; // 여기서 메소드를 호출할 겁니다.
this.rememberThisInput = myInput; // 언젠가 미래의 특정 시점에 입력할 거에요! YAY!
return (
<div>
<div>...</div>
{myInput}
</div>
);
}
```
이 반례에서 `<input />`은 단지 `<input />`의 *서술*일 뿐입니다. 이 서술은 `<input />`에 대한 *진짜* **지원 인스턴스(backing instance)**를 생성하는 데 사용됩니다.
자 그럼 어떻게 *진짜* input의 지원 인스턴스를 다룰까요?
## ref 문자열 어트리뷰트
React는 `render()`로 출력된 컴포넌트에 추가할 수 있는 아주 특별한 프로퍼티를 지원합니다. 이 특별한 프로퍼티는 `render()`에서 반환한 모든 것들에 대해 각각에 대응하는 **지원 인스턴스**를 참조할 수 있습니다. 이는 항상 어떤 시점에서든 올바른 인스턴스를 보장합니다.
간단합니다:
1. `render`에서 반환된 값을 `ref` 어트리뷰트에 할당합니다:
```html
<input ref="myInput" />
```
2. 다른 코드(일반적으로는 이벤트 핸들러 코드)에서 `this.refs`를 통해 **지원 인스턴스**에 접근 합니다:
```javascript
this.refs.myInput
```
`React.findDOMNode(this.refs.myInput)`를 호출해 컴포넌트의 DOM 노드에 접근할 수 있습니다.
## ref 콜백 어트리뷰트
`ref` 어트리뷰트는 이름 대신 콜백 함수가 될 수도 있습니다. 이 콜백은 컴포넌트가 마운트 된 뒤 즉시 실행될 것입니다. 참조된 컴포넌트는 매개 변수로 전달되며 콜백은 이를 즉시 사용하거나, 앞으로 사용하기 위해 참조를 저장해 놓거나, 혹은 둘 다 할 것입니다.
`render`에서 반환한 모든 것에 간단하게 `ref` 어트리뷰트를 할당할 수 있습니다:
```html
<input ref={ function(component){ React.findDOMNode(component).focus();} } />
```
## 예제 완성하기
```javascript
var App = React.createClass({
getInitialState: function() {
return {userInput: ''};
},
handleChange: function(e) {
this.setState({userInput: e.target.value});
},
clearAndFocusInput: function() {
// input을 비워준다
this.setState({userInput: ''}, function() {
// 이 코드는 컴포넌트가 다시 렌더 된 다음 실행됩니다
React.findDOMNode(this.refs.theInput).focus(); // 짠! 포커스 됨!
});
},
render: function() {
return (
<div>
<div onClick={this.clearAndFocusInput}>
클릭해서 초기화하고 포커스주기
</div>
<input
ref="theInput"
value={this.state.userInput}
onChange={this.handleChange}
/>
</div>
);
}
});
```
이 예제에서 render 함수는 `<input />` 인스턴스의 서술을 반환했지만, 진짜 인스턴스는 `this.refs.theInput`을 통해 접근할 수 있었습니다. render에서 `ref="theInput"`을 가진 컴포넌트가 반환된 동안, `this.refs.theInput`은 적절한 인스턴스에 접근합니다. 이는 `<Typeahead ref="myTypeahead" />`처럼 DOM이 아닌 고수준의 컴포넌트에서도 동작합니다.
## 요약
Refs는 반응적인 `props``state` 스트리밍을 통해서는 불편했던 특정한 자식 인스턴스에 메시지 보내기를 수행하는 좋은 방법입니다. 하지만 애플리케이션의 데이터 플로우 전반에 사용해도 되는 go-to 같은 개념은 아닙니다. 기본적으로는 반응적인 데이터 플로우를 사용하고, `ref`는 근본적으로 반응적이지 않은 경우에만 사용하세요.
### 이점:
- 컴포넌트 클래스에 public 메소드(ex. Typeahead의 reset)를 선언할 수 있으며 refs를 통해 그를 호출할 수 있습니다. (ex. `this.refs.myTypeahead.reset()`)
- DOM을 측정하기 위해서는 거의 항상 `<input />` 같은 "기본" 컴포넌트를 다루고 `React.findDOMNode(this.refs.myInput)`를 통해 그 기저의 DOM 노드에 접근해야 합니다. Refs는 이 일을 확실하게 수행하는 몇 안 되는 실용적인 방법의 하나입니다.
- Refs는 자동으로 기록을 관리합니다! 자식이 파괴되면, 그의 ref도 마찬가지로 파괴됩니다. 참조를 유지하기 위해 뭔가 미친 짓을 하지 않는 한, 메모리 걱정은 하지 않아도 됩니다.
### 주의:
- 컴포넌트의 렌더 메소드에서는, 혹은 컴포넌트의 렌더 메소드가 콜스택 어디에서든 실행되는 동안에는 절대 접근하지 마세요.
- Google Closure Compiler에서의 분쇄 복원력 유지(to preserve Crushing resilience)를 위해서는 문자열로 정의한 것을 절대 프로퍼티로 접근하지 마세요. ref가 ref="myRefString"으로 정의되어 있다면 this.refs['myRefString']으로만 접근해야 한다는 이야기 입니다.
- React로 앱을 여럿 만들어 본 경험이 없다면, 보통은 처음엔 앱에서 "무언가 일어나도록" 하는데 refs를 사용하게 될 것입니다. 이 경우, 잠시 시간을 내어 `state`가 컴포넌트 계층구조의 어느 부분에서 관리되어야 할지 비판적으로 생각해 봅시다. 대개는 state가 계층구조의 더 높은 레벨에서 "소유"하는 것이 타당함이 명확해집니다. 그렇게 함으로써 `ref`를 사용해 "무언가 일어나도록" 하려는 욕망이 대부분 제거됩니다. - 대신에 데이터 플로우를 통해 대개 원하는 바를 달성하게 될 것입니다.