3.6 React без ES6

Обычно мы определяем компонент React как класс JavaScript:


Код
    
  class Hello extends React.Component {
    render() {
      return <h3>Привет, {this.props.name}</h3>;
    }
  }
  

Если вы не используете ES6, вместо этого вы можете использовать модуль create-react-class:


Код
    
  var createReactClass = require('create-react-class');
  var Hello = createReactClass({
    render: function() {
      return <h3>Привет, {this.props.name}!</h3>;
    }
  });
  

API классов ES6 аналогичен createReactClass() за несколькими исключениями.


3.6.1 Объявление свойств по умолчанию

С функциями и классами ES6 defaultProps определяется как свойство самого компонента:


Код
    
  class Hello extends React.Component {
    // ...
  }

  Hello.defaultProps = {
    name: 'мир'
  };
  
  

С createReactClass() вам необходимо определить getDefaultProps() как функцию в передаваемом объекте:


Код
    
  var Hello = createReactClass({
    getDefaultProps: function() {
      return {
        name: 'мир'
      };
    },

    // ...

  });
  


3.6.2 Установка начального состояния

В классах ES6 вы можете определить начальное состояние, назначив this.state в конструкторе:


Код
    
  class TemperatureController extends React.Component {
    constructor(props) {
      super(props);
      this.state = {temperature: props.initialTemperature};
    }
    // ...
  }
  

С createReactClass() вы должны предоставить отдельный метод getInitialState, который возвращает исходное состояние:


Код
    
  var TemperatureController = createReactClass({
    getInitialState: function() {
      return {temperature: this.props.initialTemperature};
    },
    // ...
  });
  


3.6.3 Автопривязка

В компонентах React, объявленных как классы ES6, методы следуют той же семантике, что и обычные классы ES6. Это означает, что они не привязывают this к экземпляру автоматически. Вам нужно будет явно использовать .bind(this) в конструкторе:


Код
    
  class Trigger extends React.Component {
    constructor(props) {
      super(props);
      this.state = {isOn: false};
      // Данная строка важна!
      this.onTrigger = this.onTrigger.bind(this);
    }

    onTrigger() {
      this.setState({isOn: !this.state.isOn});
    }

    render() {
      // Так как `this.onTrigger` привязан, мы можем использовать его как обработчик события
      return (
        <button onClick={this.onTrigger}>this.state.isOn ? 'On' : 'Off'</button>
      );
    }
  }
  

С createReactClass() это необязательно, потому что он связывает все методы:


Код
    
  let Trigger = createReactClass({
    getInitialState: function() {
      return {isOn: false};
    },

    onTrigger: function() {
      this.setState({isOn: !this.state.isOn});
    },

    render: function() {
      // Так как `this.onTrigger` привязан, мы можем использовать его как обработчик события
      return (
        <button onClick={this.onTrigger}>this.state.isOn ? 'On' : 'Off'</button>
      );
    }
  });
  

Это означает, что написание классов ES6 требует немного больше шаблонного кода для обработчиков событий, но положительной стороной является несколько лучшая производительность в больших приложениях.

Если шаблонный код слишком непривлекателен для вас, вы можете включить экспериментальную возможность синтаксиса свойств класса от Babel:


Код
    
  class Trigger extends React.Component {
    constructor(props) {
      super(props);
      this.state = {isOn: false};
    }

    // ПРЕДУПРЕЖДЕНИЕ: данный синтаксис экспериментальный!
    // Использование здесь стрелки привязывает метод
    onTrigger = () => {
      this.setState({isOn: !this.state.isOn});
    }

    render() {
      return (
        <button onClick={this.onTrigger}>this.state.isOn ? 'On' : 'Off'</button>
      );
    }
  }
  

Обратите внимание, что приведенный выше синтаксис является экспериментальным и может измениться, или данная возможность может быть не добавлена в язык.

Если вы хотите перестраховаться, у вас есть несколько вариантов:

  • Свяжите методы в конструкторе.
  • Используйте стрелочные функции, например. onClick = {(e) => this.onTrigger (e)}.
  • Продолжайте использовать createReactClass.


3.6.4 Миксины

Внимание: ES6 запущен без какой-либо поддержки миксинов. Поэтому при использовании React с классами ES6 поддержка миксинов тоже не поддерживается. Разработчики обнаружили множество проблем с использованием миксинов и не рекомендуют использовать их в новом коде. Этот раздел существует только для справки.

Часто разные компоненты могут совместно использовать некоторые общие функции. Иногда их называют сквозной функциональностью . createReactClass позволяет использовать для этого устаревшую систему миксинов.

Одним из распространенных вариантов использования является компонент, который хочет обновить себя на каком-то временном интервале. Легко использовать setInterval(), но важно отменить ваш интервал, когда он вам больше не нужен, чтобы освободить память. React предоставляет методы жизненного цикла, которые позволяют вам знать, когда компонент будет создан или уничтожен. Давайте создадим простой миксин, который использует эти методы, чтобы предоставить простую функцию setInterval(), которая будет автоматически очищаться, когда ваш компонент будет уничтожен.


Код
    
  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 Timer = createReactClass({
    mixins: [SetIntervalMixin], // Использовать миксин
    getInitialState: function() {
      return {value: 0};
    },
    componentDidMount: function() {
      this.setInterval(this.increment, 1000); // Вызвать метод миксина
    },
    increment: function() {
      this.setState({value: this.state.value + 1});
    },
    render: function() {
      return (<h1>Значение: {this.state.value} секунд.</h1>);
    }
  });

  ReactDOM.render(<Timer />,  document.getElementById('root'));
  

Если компонент использует множество миксинов, и некоторые из них определяют один и тот же метод жизненного цикла (например несколько миксинов хотят выполнить некоторую очистку при уничтожении компонента), все методы жизненного цикла гарантированно будут вызваны. Методы, определенные в миксинах, выполняются в порядке перечисления миксинов в списке, после чего следует вызов данного метода в самом компоненте.