Вывод. Основными строительными блоками React являются компоненты. Эти компоненты могут обладать достаточной сложностью, чтобы требовать методов состояния и жизненного цикла. Однако некоторые из них достаточно просты, чтобы их можно было написать как чистые функции Javascript. Этот пост демонстрирует, как компонент можно переписать как функцию Javascript, а не как класс ES6.

Концептуально компоненты похожи на функции JavaScript. Они принимают произвольные входные данные (называемые реквизитами) и возвращают элементы React, описывающие, что должно появиться на экране...(т)самый простой способ определить компонент — написать функцию JavaScript (React Docs)

Во многом так же, как иногда легко переборщить с реализацией Store, такой как Redux, когда достаточно внутреннего состояния, можно легко ввести ненужные накладные расходы, достигнув полноценного класса ES6, когда функциональная реализация без сохранения состояния будет делать.

Возьмем пример ниже. Простой презентационный компонент, отображающий заголовок, подзаголовок и некоторый дополнительный контент. Для наших целей это было названо Section.

import React from 'react';
import classNames from 'classnames';
class Section extends React.Component {
  static propTypes = {
    title: React.PropTypes.string.isRequired,
    subtitle: React.PropTypes.string,
    children: PropTypes.node
  }
title = () => {
  return (
    <h2 className='section__title'>{ props.title }</h2>
  );
}
subtitle = () => {
  if (!this.props.subtitle) { return null; }
  return (
    <p className='section__subtitle'>{ props.subtitle }</p>
  );
}
render() {
  return (
    <div className={ classNames(props.className, 'section') }>
      { this.title() }
      { this.subtitle() }
      { props.children }
    </div>
  );
}
export default Section;

В приведенном выше компоненте нет ничего, что зависело бы от какой-либо реализации состояния или использовало методы жизненного цикла для реагирования на изменения. Поэтому это идеальный кандидат для написания простой функции Javascript. Первое, что нужно определить, это компонент.

import React from 'react';
import classNames from 'classnames';
let Section = (props) =>
  <div className={ classNames(props.className, 'section') }>
    ...
  </div>
;
export default Section;

Метод рендеринга был эффективно заменен на использование неявного возврата стрелочной функции ES6. Этот компонент Section теперь является чистой функцией Javascript. Точно так же можно переписать функции, возвращающие заголовок и подзаголовок.

const title = (props) => {
  return <h2 className='section__title'>{ props.title }</h2>;
}
const subtitle = (props) => {
  if (!props.subtitle) { return null; }
  return <p className='section__title'>{ props.subtitle }</p>;
}

Обратите внимание, что соответствующий объект реквизита должен быть передан в эти дополнительные функции, а не находиться в области действия класса и доступен при вызове this.props.

Кроме того, для раздела определено propTypes — и .propTypes, и .defaultProps могут быть установлены как свойства в функциональном компоненте.

Section.propTypes = {
  title:    React.PropTypes.string.isRequired,
  subtitle: React.PropTypes.string,
  children: React.PropTypes.node
};

Весь переписанный код становится компонентом Javascript без сохранения состояния.

import React from 'react';
import classNames from 'classnames';
const title = (props) => {
  return <h2 className='section__title'>{ props.title }</h2>;
}
const subtitle = (props) => {
  if (!props.subtitle) { return null; }
return <p className='section__title'>{ props.subtitle }</p>;
}
let Section = (props) =>
  <div className={ classNames(props.className, 'section') }>
    { title(props) }
    { subtitle(props) }
    { props.children }
  </div>
;
Section.propTypes = {
  title:    React.PropTypes.string.isRequired,
  subtitle: React.PropTypes.string,
  children: React.PropTypes.node
};
export default Section;

Вышеприведенное представляет собой значительно менее загроможденную реализацию компонента Section на чистом Javascript. Я согласен с предложением Джека Франклина о том, что одно из основных преимуществ функционального компонента без сохранения состояния действует как визуальный сигнал.

«Этот компонент представляет собой исключительно реквизит, визуализированный пользовательский интерфейс». Если я вижу компонент класса, мне нужно просмотреть его, чтобы увидеть, какие методы жизненного цикла он может использовать и какие у него могут быть обратные вызовы. Если я вижу FSC, я знаю, что он не делает ничего особенного.

Еще одним преимуществом этого подхода является то, что он позволяет проводить прямое модульное тестирование — нет никаких обратных вызовов или взаимодействия с пользователем для имитации. Тест заключается в том, что при передаче определенных реквизитов отображается ожидаемый контент.

Команда React привержена этой методологии. В примечаниях к выпуску для v0.14 они утверждали, что В идиоматическом коде React большинство компонентов, которые вы пишете, не будут иметь состояния, просто составляя другие компоненты. Кроме того, со временем этот подход станет более эффективным, так как мы также сможем оптимизировать производительность именно для этих компонентов, избегая ненужных проверок и выделения памяти.

С тех пор как я познакомился с этим шаблоном для написания компонентов, я пытался реализовать его везде, где это возможно. Как и различие между презентационными и функциональными компонентами, этот шаблон также влияет на ваше дизайнерское мышление. По мере того, как вы становитесь более внимательным к построению своего кода, чтобы он был как можно более простым и пригодным для повторного использования.

Дальнейшее чтение

Фоновый шум

  • Келли Ли Оуэнс – Келли Ли Оуэнс
  • Олдос Хардинг — Вечеринка
  • Элисон Кратчфилд — «Туристка в этом городе»

Полный код, включая спецификации, можно найти здесь