Когда использовать компоненты React на базе класса ES6 в сравнении с функциональными компонентами ES6 React?

213

Потратив некоторое время на изучение React, я понимаю разницу между двумя основными парадигмами создания компонентов.

У меня вопрос, когда я должен использовать какой и почему? Каковы преимущества / компромиссы одного над другим?


ES6 классы:

import React, { Component } from 'react';

export class MyComponent extends Component {
  render() {
    return (
      <div></div>
    );
  }
}

Функциональность:

const MyComponent = (props) => {
    return (
      <div></div>
    );
}

Я считаю функциональным всякий раз, когда этим компонентом не удается манипулировать состоянием, но так ли это?

Я предполагаю, что если я использую какие-либо методы жизненного цикла, лучше всего использовать компонент на основе классов.

omarjmh
источник
7
Кажется, вы уже знаете ответ.
Феликс Клинг
2
Если у вас есть компонент только с методом рендеринга, вы можете превратить его в функциональную форму. Если вам нужно нечто большее, чем функция отображения без сохранения состояния, используйте классы
just-boris
2
Чтобы быть еще более кратким, попробуйте это:const MyComponent = (props) => <div>...</div>
Вильям Симко
1
Я никогда не использую функционал, если его можно избежать. Потому что я неизбежно в конечном итоге нуждаюсь в рефакторинге на основе класса в будущем. И тогда часто нужно рефакторинг обратно в функционал после этого.
keithjgrant
В 2020 году правильный подход заключается в использовании функциональных компонентов везде, где это возможно, потому что они поддерживают хуки, а хуки (с точки зрения производительности и архитектуры) лучше, чем альтернативы.
polkovnikov.ph

Ответы:

162

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

Поскольку они легкие, написание этих простых компонентов в качестве функциональных компонентов является довольно стандартным.

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

Дополнительная информация: https://facebook.github.io/react/docs/reusable-components.html#es6-classes


РЕДАКТИРОВАТЬ : Многое из вышесказанного было правдой, до введения React Hooks.

  • componentDidUpdateможет быть скопирован с useEffect(fn), где fnэто функция для запуска при рендеринге.

  • componentDidMountМетоды можно реплицировать с помощью useEffect(fn, []): где fn- функция, запускаемая при повторном рендеринге, и []массив объектов, для которых компонент будет перерисован, если и только если хотя бы один из них изменил значение с момента предыдущего рендеринга. Поскольку их нет, useEffect()запускается один раз, на первом монтировании.

  • stateможет быть реплицировано с useState(), чье возвращаемое значение может быть преобразовано в ссылку на состояние и функцию, которая может установить состояние (т. е. const [state, setState] = useState(initState)). Пример может объяснить это более четко:

const Counter = () => {
  const [count, setCount] = useState(0)

  const increment = () => { 
    setCount(count + 1);
  }

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>+</button>
    </div>
  )
}

default export Counter

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

«Функции обработки событий переопределяются для каждого рендера в функциональных компонентах»

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

Если они есть, вы можете предотвратить переопределение функций с помощью useCallbackи useMemoхуков. Однако имейте в виду, что это может ухудшить производительность вашего микроскопического кода .

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

Джефф Казинс
источник
Как насчет функциональности, которая не сохраняет состояние, но тесно связана с компонентом, например, определяет некоторый динамический атрибут для рендеринга.
Деннис
Это лучшая статья о разнице между двумя типами компонентов в React: code.tutsplus.com/tutorials/…
Ариан Акоста,
5
Начиная с React 16.8, вы можете использовать состояние в функциональном компоненте через useStateхук.
Грег
Начиная с React 16.8, вы можете делать практически все в функциональных компонентах, и все эффекты могут быть, наконец, модульными, с минимальным влиянием на производительность.
polkovnikov.ph
1
Где вы нашли информацию, где Facebook officially recommends using functional components wherever possible?
Johannchopin
40

Всегда старайтесь по возможности использовать функции без сохранения состояния (функциональные компоненты). Существуют сценарии, в которых вам нужно использовать обычный класс React:

  • Компонент должен поддерживать состояние
  • Компонент рендерит слишком много, и вам нужно контролировать это через shouldComponentUpdate
  • Вам нужен контейнерный компонент

ОБНОВИТЬ

Теперь есть класс React, PureComponentкоторый вы можете расширить (вместо Component), который реализует свой собственный, shouldComponentUpdateкоторый позаботится о сравнении мелких объектов. Читать далее

ffxsam
источник
43
Always try to use stateless functions (functional components) whenever possible.Я прочитал, что десять человек говорят это. Тем не менее никто из них не дал объяснения почему.
Ротарети
25
In an ideal world, most of your components would be stateless functions because in the future we’ll also be able to make performance optimizations specific to these components by avoiding unnecessary checks and memory allocations. This is the recommended pattern, when possible.Дополнительная информация: facebook.github.io/react/docs/…
Диого Кардосо
2
@rotareti Я не знаю, чувствуете ли вы, что получили ответ на свой вопрос, но чистые функции намного проще понять, протестировать и поддерживать. При одинаковых параметрах они всегда отображают одно и то же. Компоненты, которые поддерживают состояние и изменяются при возникновении событий жизненного цикла, сложнее для понимания. Не сказать, что они иногда не нужны, но я надеюсь, что ясно, что если их преимущества не нужны, все, что они делают, это добавляют ненужные шаблоны и накладные расходы без каких-либо преимуществ.
door_number_three
Вы также захотите создать класс Component, если у вас есть собственные определения обработчика событий. Таким образом, вы можете предварительно связать эти обработчики событий с компонентом в конструкторе вместо создания новой новой функции при каждом рендеринге. Обратите внимание, что это не нужно, если все ваши обработчики событий происходят из реквизита.
Добес Вандермер
Обратите внимание, что цитируемая рекомендация Facebook больше не существует (см. Мой комментарий выше).
Гарретт
34

ОБНОВЛЕНИЕ март 2019

https://overreacted.io/how-are-function-components-different-from-classes/

ОБНОВЛЕНИЕ Фев 2019:

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

Их мотивация:

1.) Its hard to reuse stateful logic between components
2.) Complex components become hard to understand
3.) Classes confuse both people and machines

Функциональный компонент с хуками может делать почти все, что может делать компонент класса, без каких-либо недостатков, упомянутых выше.

Я рекомендую использовать их, как только вы сможете.

Оригинальный ответ

Функциональные компоненты не более легкие, чем компоненты на основе классов, «они работают точно как классы». - https://github.com/facebook/react/issues/5677#issuecomment-241190513

Приведенная выше ссылка немного устарела, но в документации React 16.7.0 говорится, что функциональные и классовые компоненты:

"эквивалентны с точки зрения React." - https://reactjs.org/docs/components-and-props.html#stateless-functions

По сути, нет никакой разницы между функциональным компонентом и компонентом класса, который просто реализует метод рендеринга, кроме синтаксиса.

В будущем (цитируя приведенную выше ссылку) «мы [React] могли бы добавить такие оптимизации».

Если вы пытаетесь повысить производительность за счет устранения ненужных визуализаций, оба подхода обеспечивают поддержку. memoдля функциональных компонентов и PureComponentдля классов.

- https://reactjs.org/docs/react-api.html#reactmemo

- https://reactjs.org/docs/react-api.html#reactpurecomponent

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

Galupuf
источник
1
Я думаю, что расширение каждого компонента React.Component делает код более читабельным, особенно для новых людей. Приятно, когда вы видите компонент, созданный одинаково каждый раз. Как сказал @Galupuf, у простых компонентов есть только один метод, называемый render (). Также хорошо, чтобы все расширяло React.Component, потому что, когда вы хотите начать связывать «this», иметь состояние и т. Д., Вам не нужно все реорганизовывать, вы можете просто добавить то, что вам нужно.
jeffski13
10

Начиная с React 16.8, термин «Функциональные компоненты без состояния» вводит в заблуждение, и его следует избегать, поскольку они больше не являются лицами без состояния ( React.SFC устарел , Дэн Абрамов в React.SFC ), они могут иметь состояние, они могут иметь хуки (которые действуют как методы жизненного цикла), они более или менее пересекаются с компонентами класса

Компоненты на основе классов

  • штат
  • методы жизненного цикла
  • памятка с помощью React.PureComponent

Функциональные компоненты:

Почему я предпочитаю функциональные компоненты

  • Реагировать обеспечивает useEffect крюк , который является очень четким и лаконичным способом объединить componentDidMount, componentDidUpdateи componentWillUnmountметоды жизненного цикла
  • С помощью хуков вы можете извлечь логику, которая может быть легко разделена между компонентами и тестируемой
  • меньше путаницы по поводу объема работ

Реагировать мотивацию , почему с помощью крюков (т.е. функциональных компонентов).

Karim
источник