Различия между функциональными компонентами и компонентами класса в React.
Когда я начинаю свой проект React, мой первый вопрос заключается в том, использовать ли компоненты класса или функциональные компоненты. Другой вариант — использовать оба в проекте. Надеюсь, каждый использует оба компонента в своих проектах.
React позволяет определять компоненты как классы или функции.
Прежде чем найти лучший вариант, мы собираемся создать компоненты класса и функциональные компоненты.
При создании компонента React его имя ДОЛЖНО начинаться с заглавной буквы.
Компонент класса
Чтобы определить класс компонента React, ваш класс должен быть расширен с помощью React.Component
.
Метод render()
должен быть определен в компоненте класса. Другие методы React.Component
являются необязательными, например constructor()
componentDidMount()
и т. д.
class Hello extends React.Component { render() { return <h1>Hello World!</h1>; } } const element = <Hello />; ReactDOM.render( element, document.getElementById('root') );
Функциональный компонент
Здесь мы собираемся изменить вышеуказанный компонент класса на функциональный компонент.
function Hello() { return <h1>Hello World!</h1>; } const element = <Hello />; ReactDOM.render( element, document.getElementById('root') );
Функциональные компоненты легко написать с меньшим количеством кода и легче понять. Потому что это обычная функция JavaScript, которая возвращает JSX.
Различия между функциональными компонентами и компонентами класса
Мы рассмотрим каждое различие между компонентами класса и функциональными компонентами.
- 1. Визуализация компонентов
- 2. Работа с реквизитом
- 3. Обработка состояний
- 4. Методы жизненного цикла
- 5. Доступ к дочерним компонентам
- 6. Компоненты высшего порядка
- 7. Границы ошибки
1. Визуализация компонентов
В компоненте класса метод render()
используется для рендеринга JSX путем расширения React.Component
Функциональный компонент — это обычная функция JavaScript, которая возвращает JSX.
Первые две программы являются прекрасным примером рендеринга компонентов.
// Class component class Hello extends React.Component { render() { return <h1>Hello World!</h1>; } } //Function component function Hello() { return <h1>Hello World!</h1>; } //Function component with Arrow function Hello = () => { return <h1>Hello World!</h1>; }
Победитель: функциональный компонент
Создание функционального компонента упрощается с помощью стрелочной функции. В качестве функционального компонента используется простая функция JavaScript. Нет больше метода рендеринга.
2. Работа с реквизитом
props
обозначает свойства и передается в компонент React. Он также используется для передачи данных от одного компонента к другому. Подробнее читайте в официальной Документации React.
Компонент класса с реквизитами
this.props
используется для доступа к нашим name
реквизитам.
class Hello extends React.Component { render() { return <h1>Hello {this.props.name}!</h1>; } } const element = <Hello name="World"/>; ReactDOM.render( element, document.getElementById('root') );
Функциональный компонент с реквизитами
Действительный функциональный компонент React должен иметь один аргумент для функции. Аргумент props
будет иметь все реквизиты компонента, такие как props.name
.
function Hello(props) { return <h1>Hello {props.name}!</h1>; } const element = <Hello name="World" />; ReactDOM.render( element, document.getElementById('root') );
Победитель: функциональный компонент
Не беспокойтесь о ключевом слове this
. Синтаксис чистый и простой, это победитель.
3. Состояние обработки
state
— это встроенный объект компонента React, он используется для управления поведением компонента. Когда объект state
изменится, компонент будет повторно визуализирован.
Компонент класса с состоянием
class Timenow extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } render() { return( <div> <h1>Hello {this.props.name}!</h1> <h2>Time Now {this.state.date.toLocaleTimeString()}.</h2> </div> ); } } const element = <Timenow name="World"/>; ReactDOM.render( element, document.getElementById('root') );
Метод компонентов класса constructor
используется для инициализации значений состояния.
Функциональный компонент с состоянием
В функциональном компоненте состояние обрабатывается с помощью хука useState.
Хуки — это новое дополнение к React 16.8. Они позволяют вам использовать состояние и другие функции React без написания класса.
Функциональный компонент не имеет this
, поэтому мы не можем присвоить или прочитать this.state
. Вместо этого мы вызываем хук useState
непосредственно внутри нашего функционального компонента.
function Timenow(props) { const [date, setDate] = React.useState(new Date()); return ( <div> <h1>Hello {props.name}!</h1> <h2>Time Now {date.toLocaleTimeString()}.</h2> </div> ); } const element = <Timenow name="World" />; ReactDOM.render( element, document.getElementById('root') );
Победитель: функциональный компонент
Инициализация state
выполняется с помощью хука useState
. Метод constructor
не требуется.
4. Методы жизненного цикла
В React каждый компонент имеет несколько методов lifecycle
, этот метод помогает вам запускать код в определенное время в процессе. Нажмите здесь, чтобы просмотреть схему жизненного цикла React.
Компонент класса с методами жизненного цикла
Приведенный ниже компонент класса часов является прекрасным примером реализации методов жизненного цикла.
class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } componentDidMount() { this.timerID = setInterval( () => this.tick(), 1000 ); } componentWillUnmount() { clearInterval(this.timerID); } tick() { this.setState({ date: new Date() }); } render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div> ); } } ReactDOM.render( <Clock />, document.getElementById('root') );
Функциональный компонент с методами подключения жизненного цикла
Мы преобразовали вышеуказанный компонент класса clock
в функциональный компонент с помощью хука useEffect
.
Метод возврата useEffect
используется для очистки.
function Clock(props) { const [date, setDate] = React.useState(new Date()); React.useEffect(() => { var timerID = setInterval(() => tick(), 1000); return function cleanup() { clearInterval(timerID); }; }); function tick() { setDate(new Date()); } return ( <div> <h1>Hello, world!</h1> <h2>It is {date.toLocaleTimeString()}.</h2> </div> ); } ReactDOM.render( <Clock />, document.getElementById('root') );
Победитель: Компонент класса
Функциональный компонент useEffect
сбивает с толку из-за использования одного и того же хука для всех методов жизненного цикла. В компоненте класса мы можем напрямую использовать методы componentDidMount
, componentWillUnmount
и т.д.
5. Доступ к дочерним компонентам
Специальная реквизита children
используется для доступа к компоненту внутри контента или компоненту, например ‹Layout›внутри контента‹/Layout›.
Компонент класса
this.props.children
используется для компонентов класса.
class Layout extends React.Component { render() { return( <div> <h1>Hello {this.props.name}!</h1> <div>{this.props.children}</div> </div> ); } } const element = <Layout name="World">This is layout content</Layout>; ReactDOM.render( element, document.getElementById('root') );
Функциональный компонент
Просто props.children
используется в функциональных компонентах для доступа к дочернему контенту.
function Layout(props) { return( <div> <h1>Hello {props.name}!</h1> <div>{props.children}</div> </div> ); } const element = <Layout name="World">This is layout content</Layout>; ReactDOM.render( element, document.getElementById('root') );
Победитель: класс и функциональный компонент
Оба используют один и тот же props.children
для доступа к дочерним компонентам. Кроме того, нам нужно использовать ключевое слово this
.
6. Компоненты высшего порядка
Компонент высшего порядка (HOC) — это продвинутая техника в React для повторного использования логики компонентов. HOC — это чистая функция, поэтому она возвращает только новый компонент.
Компонент высшего порядка — это функция, которая принимает компонент и возвращает новый компонент.
HOC с компонентом класса
function classHOC(WrappedComponent) { return class extends React.Component{ render() { return <WrappedComponent {...this.props}/>; } } } const Hello = ({ name }) => <h1>Hello {name}!</h1>; const NewComponent = classHOC(Hello); const element = <NewComponent name="World" />; ReactDOM.render( element, document.getElementById('root') );
HOC с функциональным компонентом
function functionalHOC(WrappedComponent) { return (props) => { return <WrappedComponent {...props}/>; } } const Hello = ({ name }) => <h1>Hello {name}!</h1>; const NewComponent = functionalHOC(Hello); const element = <NewComponent name="World" />; ReactDOM.render( element, document.getElementById('root') );
Победитель: функциональный компонент
Чтобы создать HOC, мы должны использовать функцию JavaScript (classHOC, functionHOC). Не используйте HOC внутри метода рендеринга. Внутри функции мы можем использовать класс или функциональные компоненты.
7. Границы ошибки
Границы ошибок — это компоненты React, используемые для обработки ошибок JavaScript в компонентах React. Таким образом, мы можем отлавливать ошибки времени выполнения JavaScript в наших компонентах и отображать резервный пользовательский интерфейс.
Границы ошибок — это компоненты React, которые перехватывают ошибки JavaScript в любом месте своего дочернего дерева компонентов, регистрируют эти ошибки и отображают резервный пользовательский интерфейс вместо дерева компонентов, в котором произошел сбой.
Использование методов жизненного цикла static getDerivedStateFromError()
или componentDidCatch()
означает, что компонент класса становится границей ошибки. Используйте static getDerivedStateFromError()
для отображения резервного пользовательского интерфейса после возникновения ошибки. Используйте componentDidCatch()
для регистрации информации об ошибке.
Границы ошибок работают как блок JavaScript catch {}
, но для компонентов.
Простой пример с границами ошибок
class ErrorCounter extends React.Component { constructor(props) { super(props); this.state = {error: null, errorInfo: null}; } componentDidCatch(error, errorInfo) { // Catch errors in any components below and re-render with error message this.setState({ error: error, errorInfo: errorInfo }) // You can also log error messages to an error reporting service here } refreshPage() { history.go(-1) } render() { if (this.state.errorInfo) { // Error path return ( <div> <h2>Something went wrong.</h2> <details style={{ whiteSpace: 'pre-wrap' }}> {this.state.error && this.state.error.toString()} <br /> {this.state.errorInfo.componentStack} </details> <hr /> <button onClick={this.refreshPage}> Refresh Page </button> </div> ); } // Normally, just render children return this.props.children; } }; class Counter extends React.Component { constructor(props) { super(props); this.state = { counter: 0 }; this.handleClick = this.handleClick.bind(this); } handleClick() { this.setState(({counter}) => ({ counter: counter + 1 })); } render() { if (this.state.counter === 3) { // Simulate a JS error throw new Error('I crashed!'); } return( <div> <h1>{this.state.counter}</h1> <button onClick={this.handleClick}>+</button> </div> ); } } ReactDOM.render( <ErrorCounter> <Counter /> </ErrorCounter>, document.getElementById('root') );
Победитель: Компонент класса
В настоящее время только компоненты класса могут быть границами ошибок.
Вывод: что лучше?
В настоящее время большинство приложений используют функциональные компоненты из-за их простоты, простоты использования и понимания. Также функциональные компоненты стали очень известны после появления хуков в React v16.8.
Методы жизненного цикла в функциональных компонентах просты в использовании благодаря хукам.
Компоненты классов трудно понять новичкам, которые не имеют опыта работы с ES6 JavaScript, где были представлены классы.
В отличие от других языков программирования, таких как Java, PHP и C#, классы JavaScript — это синтаксический сахар, а не наследование прототипов. Другими словами, классы ES6 — это просто специальные функции. Поэтому мы не можем использовать функции класса в классах JavaScript.
Компоненты класса играют важную роль в обработке ошибок. Поскольку компонент класса поддерживает только методы жизненного цикла границ ошибок static getDerivedStateFromError()
или componentDidCatch()
.
Нет ничего лучше, потому что у обоих есть плюсы и минусы. Но компоненты класса важны для понимания потока React и методов жизненного цикла.
Новому учащемуся следует попрактиковаться в React, используя компоненты класса. Как только они познакомятся с компонентами класса, они смогут изучать и использовать функциональные компоненты.
Спасибо за чтение! Не стесняйтесь комментировать свои отзывы и делиться недостающими различиями между компонентами класса и функциональными компонентами.
Ссылки
https://reactjs.org/docs/react-component.html https://reactjs.org/docs/components-and-props.html https://reactjs.org/docs/state-and-lifecycle.html https://reactjs.org/docs/higher-order-components.html https://www.twilio.com/blog/react-choose-functional-components https://blog.logrocket.com/handling-javascript-errors-react-error-boundaries/
Дальнейшее чтение
Дополнительные материалы на PlainEnglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter, LinkedIn, YouTube и Discord . Заинтересованы в хакинге роста? Ознакомьтесь с разделом Схема.