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.
 
 
 
 

8.0 KiB

id title permalink prev next
more-about-refs-ko-KR refs 심화 more-about-refs-ko-KR.html working-with-the-browser-ko-KR.html tooling-integration-ko-KR.html

render 메소드를 통해 UI 구조를 얻은 다음, 반환된 컴포넌트 인스턴스에 접근하거나 메소드를 호출할 방법이 필요할 수도 있습니다. 반응적 데이터 플로우가 render()의 결과물에서 최신의 props가 각각의 자식으로 보내진 것을 항상 보장하기 때문에 애플리케이션의 데이터 플로우를 만드는데 대체로 이런 작업은 필요가 없지만, 여전히 이런 작업이 필요하거나 유리한 경우가 있긴 합니다.

인스턴스의 하위 계층구조에 존재하는 <input /> 엘리먼트의 value를 빈 문자열('')로 업데이트한 후 포커스 하는 경우를 생각해 봅시다.

  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()에서 반환된 무언가를 "계속 유지할 수" 없으며 아무런 의미도 없을 것이라는 뜻입니다.

  // 반례: 이렇게 하면 안됩니다!
  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 어트리뷰트에 할당합니다:
<input ref="myInput" />
  1. 다른 코드(일반적으로는 이벤트 핸들러 코드)에서 this.refs를 통해 지원 인스턴스에 접근 합니다:
this.refs.myInput

React.findDOMNode(this.refs.myInput)를 호출해 컴포넌트의 DOM 노드에 접근할 수 있습니다.

ref 콜백 어트리뷰트

ref 어트리뷰트는 이름 대신 콜백 함수가 될 수도 있습니다. 이 콜백은 컴포넌트가 마운트 된 뒤 즉시 실행될 것입니다. 참조된 컴포넌트는 매개 변수로 전달되며 콜백은 이를 즉시 사용하거나, 앞으로 사용하기 위해 참조를 저장해 놓거나, 혹은 둘 다 할 것입니다.

render에서 반환한 모든 것에 간단하게 ref 어트리뷰트를 할당할 수 있습니다:

<input ref={ function(component){ React.findDOMNode(component).focus();} } />

예제 완성하기

  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는 반응적인 propsstate 스트리밍을 통해서는 불편했던 특정한 자식 인스턴스에 메시지 보내기를 수행하는 좋은 방법입니다. 하지만 애플리케이션의 데이터 플로우 전반에 사용해도 되는 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를 사용해 "무언가 일어나도록" 하려는 욕망이 대부분 제거됩니다. - 대신에 데이터 플로우를 통해 대개 원하는 바를 달성하게 될 것입니다.