--- 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`가 각각의 자식으로 보내진 것을 항상 보장하기 때문에 애플리케이션의 데이터 플로우를 만드는데 대체로 이런 작업은 필요가 없지만, 여전히 이런 작업이 필요하거나 유리한 경우가 있긴 합니다. 인스턴스의 하위 계층구조에 존재하는 `` 엘리먼트의 value를 빈 문자열(`''`)로 업데이트한 후 포커스 하는 경우를 생각해 봅시다. ```javascript var App = React.createClass({ getInitialState: function() { return {userInput: ''}; }, handleChange: function(e) { this.setState({userInput: e.target.value}); }, clearAndFocusInput: function() { this.setState({userInput: ''}); // 입력내용을 지워줍니다 // 이제 에 포커스를 주길 원합니다! }, render: function() { return (
클릭해서 초기화하고 포커스주기
); } }); ``` 한번 살펴보죠. 이 예제에서 우리는 시간이 지남에 따라 props에서 추론할 수 없는 무언가를 입력하도록 "알려주길" 원했습니다. 이 사례에서 우리는 이제 포커스 되도록 "알려주길" 원합니다. 그러나 몇 가지 문제가 있습니다. `render()`에서 반환된 것은 "자식" 컴포넌트의 실제 구성이 아니고, 단지 특정 시점의 인스턴스의 자식에 대한 *서술*일 뿐입니다. - 말하자면 스냅샷인 것이지요. > 주의: > > 기억하세요, `render()`에서 반환된 것은 *실제* 자식 인스턴스가 아닙니다. 단지 특정 시점의 컴포넌트의 하위 계층구조에 있는 자식 인스턴스의 *서술*일 뿐입니다. 이는 `render()`에서 반환된 무언가를 "계속 유지할 수" 없으며 아무런 의미도 없을 것이라는 뜻입니다. ```javascript // 반례: 이렇게 하면 안됩니다! render: function() { var myInput = ; // 여기서 메소드를 호출할 겁니다. this.rememberThisInput = myInput; // 언젠가 미래의 특정 시점에 입력할 거에요! YAY! return (
...
{myInput}
); } ``` 이 반례에서 ``은 단지 ``의 *서술*일 뿐입니다. 이 서술은 ``에 대한 *진짜* **지원 인스턴스(backing instance)**를 생성하는 데 사용됩니다. 자 그럼 어떻게 *진짜* input의 지원 인스턴스를 다룰까요? ## ref 문자열 어트리뷰트 React는 `render()`로 출력된 컴포넌트에 추가할 수 있는 아주 특별한 프로퍼티를 지원합니다. 이 특별한 프로퍼티는 `render()`에서 반환한 모든 것들에 대해 각각에 대응하는 **지원 인스턴스**를 참조할 수 있습니다. 이는 항상 어떤 시점에서든 올바른 인스턴스를 보장합니다. 간단합니다: 1. `render`에서 반환된 값을 `ref` 어트리뷰트에 할당합니다: ```html ``` 2. 다른 코드(일반적으로는 이벤트 핸들러 코드)에서 `this.refs`를 통해 **지원 인스턴스**에 접근 합니다: ```javascript this.refs.myInput ``` `React.findDOMNode(this.refs.myInput)`를 호출해 컴포넌트의 DOM 노드에 접근할 수 있습니다. ## ref 콜백 어트리뷰트 `ref` 어트리뷰트는 이름 대신 콜백 함수가 될 수도 있습니다. 이 콜백은 컴포넌트가 마운트 된 뒤 즉시 실행될 것입니다. 참조된 컴포넌트는 매개 변수로 전달되며 콜백은 이를 즉시 사용하거나, 앞으로 사용하기 위해 참조를 저장해 놓거나, 혹은 둘 다 할 것입니다. `render`에서 반환한 모든 것에 간단하게 `ref` 어트리뷰트를 할당할 수 있습니다: ```html ``` ## 예제 완성하기 ```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 (
클릭해서 초기화하고 포커스주기
); } }); ``` 이 예제에서 render 함수는 `` 인스턴스의 서술을 반환했지만, 진짜 인스턴스는 `this.refs.theInput`을 통해 접근할 수 있었습니다. render에서 `ref="theInput"`을 가진 컴포넌트가 반환된 동안, `this.refs.theInput`은 적절한 인스턴스에 접근합니다. 이는 ``처럼 DOM이 아닌 고수준의 컴포넌트에서도 동작합니다. ## 요약 Refs는 반응적인 `props`와 `state` 스트리밍을 통해서는 불편했던 특정한 자식 인스턴스에 메시지 보내기를 수행하는 좋은 방법입니다. 하지만 애플리케이션의 데이터 플로우 전반에 사용해도 되는 go-to 같은 개념은 아닙니다. 기본적으로는 반응적인 데이터 플로우를 사용하고, `ref`는 근본적으로 반응적이지 않은 경우에만 사용하세요. ### 이점: - 컴포넌트 클래스에 public 메소드(ex. Typeahead의 reset)를 선언할 수 있으며 refs를 통해 그를 호출할 수 있습니다. (ex. `this.refs.myTypeahead.reset()`) - DOM을 측정하기 위해서는 거의 항상 `` 같은 "기본" 컴포넌트를 다루고 `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`를 사용해 "무언가 일어나도록" 하려는 욕망이 대부분 제거됩니다. - 대신에 데이터 플로우를 통해 대개 원하는 바를 달성하게 될 것입니다.