ES6를 사용하지않는 React

보통 React 컴포넌트는 순수 자바스크립트 클래스로 정의합니다.

class Greeting extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

아직 ES6를 사용하지않는다면 클래스 대신 create-react-class 를 사용할 수 있습니다.

var createReactClass = require('create-react-class');
var Greeting = createReactClass({
  render: function() {
    return <h1>Hello, {this.props.name}</h1>;
  }
});

ES6 클래스 API는 일부 예외를 제외하고 createReactClass() 와 비슷합니다.

기본 Props 선언하기

ES6 클래스 defaultProps 와 함수를 통해 컴포넌트 자체에 속성을 정의할수 있습니다.

class Greeting extends React.Component {
  // ...
}

Greeting.defaultProps = {
  name: 'Mary'
};

createReactClass() 를 이용할 때는 객체에 함수를 전달하기 위해 getDefaultProps() 를 정의할 필요가 있습니다.

var Greeting = createReactClass({
  getDefaultProps: function() {
    return {
      name: 'Mary'
    };
  },

  // ...

});

초기 state 설정하기

ES6 클래스에서 생성자에서 this.state 를 할당하여 초기 state를 정의할 수 있습니다.

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {count: props.initialCount};
  }
  // ...
}

createReactClass() 를 이용할 때는 기초 state를 반환하는 개별 getInitialState 메서드를 사용합니다.

var Counter = createReactClass({
  getInitialState: function() {
    return {count: this.props.initialCount};
  },
  // ...
});

Autobinding

ES6로 선언한 React 컴포넌트에서 메서드는 보통 ES6 클래스와 동일한 의미를 가져갑니다. 이는 인스턴스에서 this 가 자동으로 바인딩되지 않음을 의미합니다. 생성자에서 .bind(this) 를 사용해야합니다.

class SayHello extends React.Component {
  constructor(props) {
    super(props);
    this.state = {message: 'Hello!'};
    // This line is important!
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    alert(this.state.message);
  }

  render() {
    // Because `this.handleClick` is bound, we can use it as an event handler.
    return (
      <button onClick={this.handleClick}>
        Say hello
      </button>
    );
  }
}

createReactClass() 에서는 모든 메서드를 바인드하기 때문에 유효하지 않습니다.

var SayHello = createReactClass({
  getInitialState: function() {
    return {message: 'Hello!'};
  },

  handleClick: function() {
    alert(this.state.message);
  },

  render: function() {
    return (
      <button onClick={this.handleClick}>
        Say hello
      </button>
    );
  }
});

즉 ES6 클래스를 사용하면 이벤트 핸들러에서 더 많은 보일러플레이트 코드를 필요로 하지만 큰 어플리케이션에서는 성능이 약간 향상됩니다.

보일러플레이트 코드가 매력없어보인다면 Babel을 사용하여 실험 기능인 Class Properties 제안 구문을 사용할 수도 있습니다.

class SayHello extends React.Component {
  constructor(props) {
    super(props);
    this.state = {message: 'Hello!'};
  }
  // WARNING: this syntax is experimental!
  // Using an arrow here binds the method:
  handleClick = () => {
    alert(this.state.message);
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        Say hello
      </button>
    );
  }
}

위 구문은 실험 기능 이며 언어에서 명확히 제안되지 않았기 때문에 구문이 변할 수 있다는 점을 명심하시길 바랍니다.

오히려 안전하게 사용하기위한 몇가지 방법이 있습니다.

  • 생성자에서 Bind 메서드 사용하기
  • arrow 함수 사용하기. 즉 onClick={(e) => this.handleClick(e)}.
  • 계속 createReactClass 사용하기.

Mixins

Note:

mixin 지원 없이 ES6가 출시되었습니다. 따라서 React ES6 클래스를 사용하면 mixin을 지원하지 않습니다.

mixin을 사용한 코드베이스에서 수많은 이슈를 발견하였으며 새 코드에서 이를 사용하지 않는 것을 권장합니다.

이 섹션은 레퍼런스를 위해 존재합니다.

가끔 아주 다른 컴포넌트끼리 같은 기능을 공유할 수도 있습니다. 이는 가끔 cross-cutting concerns 라고 불립니다. createReactClass 는 이를 위해 레거시 mixins 시스템을 사용합니다.

한 일반적인 사용 사례는 시간 interval에 따라 컴포넌트 자체가 업데이트하려는 컴포넌트입니다. setInterval() 을 사용하는 건 쉽지만 메모리를 절약하기 위해 더 이상 필요하지 않을 때 interval을 취소시키는 것이 중요합니다. React는 컴포넌트의 생성 및 제거 시점을 알려주는 라이프사이클 메서드 를 제공합니다. 이 메서드를 사용하여 컴포넌트가 제거될 때 자동으로 정리되는 쉬운 setInterval() 함수를 제공하는 간단한 mixin을 만들어봅시다.

var SetIntervalMixin = {
  componentWillMount: function() {
    this.intervals = [];
  },
  setInterval: function() {
    this.intervals.push(setInterval.apply(null, arguments));
  },
  componentWillUnmount: function() {
    this.intervals.forEach(clearInterval);
  }
};

var createReactClass = require('create-react-class');

var TickTock = createReactClass({
  mixins: [SetIntervalMixin], // Use the mixin
  getInitialState: function() {
    return {seconds: 0};
  },
  componentDidMount: function() {
    this.setInterval(this.tick, 1000); // Call a method on the mixin
  },
  tick: function() {
    this.setState({seconds: this.state.seconds + 1});
  },
  render: function() {
    return (
      <p>
        React has been running for {this.state.seconds} seconds.
      </p>
    );
  }
});

ReactDOM.render(
  <TickTock />,
  document.getElementById('example')
);

컴포넌트가 여러개의 mixin을 사용하고 여러 mixin이 동일한 라이프사이클 메서드를 정의하는 경우 (즉 컴포넌트가 제거될 때 여러 mixin이 클린업을 수행하려는 경우) 모든 라이프사이클 메서드가 호출되도록 보장합니다. mixin에 정의된 메서드는 mixin된 순서대로 작동하고 그 후에 컴포넌트에 대한 메소드 호출이 따라옵니다.