Функциональные компоненты react: Чем функциональные компоненты React отличаются от компонентов, основанных на классах?
функциональные компоненты / Блог компании RUVDS.com / Хабр
В одном из наших предыдущих материалов мы задавали вам вопрос о том, целесообразно ли сделать на базе этого курса по React серию традиционных публикаций. Вы нашу идею поддержали. Поэтому сегодня мы представляем вашему внимание продолжение курса. Здесь мы поговорим о функциональных компонентах.
→ Часть 1: обзор курса, причины популярности React, ReactDOM и JSX
→ Часть 2: функциональные компоненты
→ Часть 3: файлы компонентов, структура проектов
→ Часть 4: родительские и дочерние компоненты
→ Часть 5: начало работы над TODO-приложением, основы стилизации
→ Часть 6: о некоторых особенностях курса, JSX и JavaScript
→ Часть 7: встроенные стили
→ Часть 8: продолжение работы над TODO-приложением, знакомство со свойствами компонентов
→ Часть 9: свойства компонентов
→ Часть 10: практикум по работе со свойствами компонентов и стилизации
→ Часть 11: динамическое формирование разметки и метод массивов map
→ Часть 12: практикум, третий этап работы над TODO-приложением
→ Часть 13: компоненты, основанные на классах
→ Часть 14: практикум по компонентам, основанным на классах, состояние компонентов
→ Часть 15: практикумы по работе с состоянием компонентов
→ Часть 16: четвёртый этап работы над TODO-приложением, обработка событий
→ Часть 17: пятый этап работы над TODO-приложением, модификация состояния компонентов
→ Часть 18: шестой этап работы над TODO-приложением
→ Часть 19: методы жизненного цикла компонентов
→ Часть 20: первое занятие по условному рендерингу
→ Часть 21: второе занятие и практикум по условному рендерингу
→ Часть 22: седьмой этап работы над TODO-приложением, загрузка данных из внешних источников
→ Часть 23: первое занятие по работе с формами
→ Часть 24: второе занятие по работе с формами
→ Часть 25: практикум по работе с формами
→ Часть 26: архитектура приложений, паттерн Container/Component
→ Часть 27: курсовой проект
Занятие 6. Функциональные компоненты
→ Оригинал
На предыдущем практическом занятии мы говорили о том, что необязательно размещать весь JSX-код, формирующий HTML-элементы, в аргументе метода ReactDOM.render()
. В нашем случае речь идёт о маркированном списке, таком, описание которого представлено ниже.
import React from "react"
import ReactDOM from "react-dom"
ReactDOM.render(
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>,
document.getElementById("root")
)
Представьте себе, что надо вывести, пользуясь таким же подходом, целую веб-страницу, на которой имеются сотни элементов. Если это сделать, то нормально поддерживать такой код будет практически невозможно. Когда мы говорили о причинах популярности React, одной из них была поддержка этой библиотекой компонентов, подходящих для повторного использования. Сейчас мы поговорим о том, как создавать функциональные компоненты React.
Эти компоненты называются «функциональными» из-за того, что создают их, конструируя особые функции.
Создадим новую функцию и дадим ей имя MyApp
:
import React from "react"
import ReactDOM from "react-dom"
function MyApp() {
}
ReactDOM.render(
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>,
document.getElementById("root")
)
Имя функции сделано именно таки по той причине, что здесь используется схема именования функций-конструкторов. Их имена (фактически — имена компонентов) записываются в верблюжьем стиле — первые буквы слов, из которых они состоят, делаются заглавными, в том числе — первая буква первого слова. Вам следует строго придерживаться этого соглашения об именовании подобных функций.
Функциональные компоненты устроены довольно просто. А именно, в теле функции должна быть команда, возвращающая JSX-код, который и представляет соответствующий компонент.
В нашем примере достаточно взять код маркированного списка и организовать возврат этого кода из функционального компонента. Вот как это может выглядеть:
function MyApp() {
return <ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
}
И хотя в данном случае всё будет работать так, как ожидается, то есть, команда return
вернёт весь этот код, рекомендуется заключать подобные конструкции в круглые скобки и применять ещё одно соглашение, принятое в React при форматировании кода программ. Оно заключается в том, что отдельные элементы помещают на отдельных строках и соответствующим образом выравнивают. В результате применения вышеописанных идей код нашего функционального компонента будет выглядеть так:
function MyApp() {
return (
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
)
}
При таком подходе возвращаемая из компонента разметка оказывается очень похожей на обычный HTML-код.
Теперь, в методе ReactDOM.render()
, можно создать экземпляр нашего функционального компонента, передав его этому методу в качестве первого аргумента и заключив его в JSX-тег.
import React from "react"
import ReactDOM from "react-dom"
function MyApp() {
return (
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
)
}
ReactDOM.render(
<MyApp />,
document.getElementById("root")
)
Можно заметить, что тут использован самозакрывающийся тег. В некоторых случаях, когда нужно создавать компоненты, имеющие более сложную структуру, подобные конструкции строятся иначе, но пока мы будем пользоваться именно такими самозакрывающимися тегами.
Если обновить страницу, сформированную средствами вышеприведённого кода, то её внешний вид будет таким же, каким он был до выноса разметки маркированного списка в функциональный компонент.
Разметка, которую возвращают функциональные компоненты, подчиняется тем же правилам, которые мы рассматривали в применении к первому параметру метода ReactDOM.render()
. То есть — нельзя, чтобы в ней присутствовали JSX-элементы, следующие друг за другом. Попытка поместить в предыдущем примере после элемента <ul>
любой другой элемент, скажем — <ol>
, приведёт к ошибке. Избежать этой проблемы можно, например, просто обернув всё, что возвращает функциональный компонент, в элемент <div>
.
Возможно, вы уже начали ощущать то, какие мощные возможности даёт нам использование функциональных компонентов. В частности, речь идёт о создании собственных компонентов, которые содержат фрагменты JSX-кода, представляющие собой описание HTML-разметки, которая окажется на веб-странице. Такие компоненты можно компоновать друг с другом.
В нашем примере имеется компонент, выводящий простой HTML-список, но, по мере того, как мы будем создавать всё более сложные приложения, мы будем разрабатывать компоненты, выводящие другие созданные нами компоненты. В итоге всё это будет превращаться в обычные HTML-элементы, но иногда для формирования этих элементов понадобятся, возможно, десятки собственных компонентов.
В итоге, когда мы будем создавать всё больше компонентов, мы будем размещать их в отдельных файлах, но пока вам важно освоить то, что мы только что обсудили, привыкнуть к функциональным компонентам. В процессе прохождения курса вы будете создавать всё более и более сложные файловые структуры.
На этом занятии мы разобрали основы функциональных компонентов, а на следующем применим полученные знания на практике.
Занятие 7. Практикум. Функциональные компоненты
→ Оригинал
▍Задание
- Подготовьте базовый React-проект.
- Создайте функциональный компонент
MyInfo
, формирующий следующие HTML-элементы:- Элемент
<h2>
с вашим именем. - Текстовый абзац (элемент
<p>
), содержащий ваш краткий рассказ о себе. - Список, маркированный (
<ul>
) или нумерованный (<ol>
), с перечнем трёх мест, которые вам хотелось бы посетить.
- Элемент
- Выведите экземпляр компонента
MyInfo
на веб-страницу.
▍Дополнительное задание
Стилизуйте элементы страницы, самостоятельно узнав о том, как это сделать (поищите в Google). Надо отметить, что о стилизации компонентов мы в этом курсе ещё поговорим.
Примечание: сворачиваемый блок
▍Решение
Тут нас устроит такая же HTML-страница, которой мы пользовались ранее. Файл с React-кодом тоже будет выглядеть вполне стандартно. А именно, импортируем в него библиотеки, создадим каркас функционального компонента MyInfo
и вызовем метод render()
объекта ReactDOM
, передав ему компонент, который надо вывести на страницу, и ссылку на элемент страницы, в котором должен быть выведен этот компонент. На данном этапе работы код будет выглядеть так:
import React from "react"
import ReactDOM from "react-dom"
function MyInfo() {
}
ReactDOM.render(<MyInfo />, document.getElementById("root"))
Теперь нужно вернуть из MyInfo
JSX-код, формирующий HTML-разметку в соответствии с заданием. Вот полный код решения.
import React from "react"
import ReactDOM from "react-dom"
function MyInfo() {
return (
<div>
<h2>Bob Ziroll</h2>
<p>This is a paragraph about me...</p>
<ul>
<li>Thailand</li>
<li>Japan</li>
<li>Nordic Countries</li>
</ul>
</div>
)
}
ReactDOM.render(
<MyInfo />,
document.getElementById("root")
)
Обратите внимание на то, что конструкция, возвращаемая из MyInfo
, заключена в круглые скобки, и на то, что элементы, которые нужно вывести, находятся внутри вспомогательного элемента <div>
.
Итоги
В этом материале мы познакомились с функциональными компонентами React. В следующий раз поговорим о файлах компонентов и о структуре React-проектов.
Уважаемые читатели! Если вы проходите этот курс — просим рассказать о том, в какой среде вы выполняете упражнения.
Функциональные компоненты / Хабр
Как говорится, в редакцию пришло письмо: «не могли бы вы подробно разъяснить…» Отвечаю публично, кому оно надо, а применение можно пощупать тут.
Сначала были компоненты на классах:
class Square extends React.Component {
constructor() {
super()
this.state = {
value: null,
}
}
render() {
const { value, onClick } = this.props
return (
<button className="square" onClick={onClick}>
{value}
</button>
)
}
}
Потом явились функциональные компоненты:
const Square = ({ value, onClick }) => {(
<button className="square" onClick={onClick}>
{value}
</button>
)}
В чём разница? Выкидываем: объявление класса, constructor(), render(), const для деструктуризации props, this. А ещё исчезло состояние компонента — мы получаем stateless functional components.
Как дальше жить без локального состояния: 1) или применять функциональные компоненты только там, где не нужно хранить состояние; 2) или перенести всё состояние в стор redux-а (как единственный источник правды). Локальные состояния компонентов — это дополнительный уровень абстракции, требующий обслуживания. А зачем?
Ещё желательно преодолеть коннектобоязнь — не тащить все свойства через родительские компоненты, а применять connect() для дочерних компонентов по мере использования свойств.
Разобрались, а как же применить PureComponent к функциональным компонентам? На помощь приходит техника Higher-Order Components:
// utils.js
import React from 'react'
export const pureComponent = (fn) => {
class Wrapper extends React.PureComponent {
render() {
return fn(this.props, this.context)
}
}
// не надо, т.к. подписывает на контекст как и функциональный компонент,
// так и оболочку-PureComponent; лучше назначать сразу оболочке (снаружи)
// Wrapper.contextTypes = fn.contextTypes
Wrapper.displayName = `PureComponent(${fn.name})`
return Wrapper
}
Присваивание displayName — для красоты в React DevTools. Подробнее про contextTypes можно почитать тут.
Пример использования:
import { pureComponent } from 'utils'
const Square = ({ value, onClick }) => {(
<button className="square" onClick={onClick}>
{value}
</button>
)}
export default pureComponent(Square)
Рекомендуемые статьи
свойства компонентов / Блог компании RUVDS.com / Хабр
В сегодняшней части перевода учебного курса по React мы поговорим о свойствах компонентов. Это — одна из важнейших концепций, нашедших отражение в данной библиотеке.
→ Часть 1: обзор курса, причины популярности React, ReactDOM и JSX
→ Часть 2: функциональные компоненты
→ Часть 3: файлы компонентов, структура проектов
→ Часть 4: родительские и дочерние компоненты
→ Часть 5: начало работы над TODO-приложением, основы стилизации
→ Часть 6: о некоторых особенностях курса, JSX и JavaScript
→ Часть 7: встроенные стили
→ Часть 8: продолжение работы над TODO-приложением, знакомство со свойствами компонентов
→ Часть 9: свойства компонентов
→ Часть 10: практикум по работе со свойствами компонентов и стилизации
→ Часть 11: динамическое формирование разметки и метод массивов map
→ Часть 12: практикум, третий этап работы над TODO-приложением
→ Часть 13: компоненты, основанные на классах
→ Часть 14: практикум по компонентам, основанным на классах, состояние компонентов
→ Часть 15: практикумы по работе с состоянием компонентов
→ Часть 16: четвёртый этап работы над TODO-приложением, обработка событий
→ Часть 17: пятый этап работы над TODO-приложением, модификация состояния компонентов
→ Часть 18: шестой этап работы над TODO-приложением
→ Часть 19: методы жизненного цикла компонентов
→ Часть 20: первое занятие по условному рендерингу
→ Часть 21: второе занятие и практикум по условному рендерингу
→ Часть 22: седьмой этап работы над TODO-приложением, загрузка данных из внешних источников
→ Часть 23: первое занятие по работе с формами
→ Часть 24: второе занятие по работе с формами
→ Часть 25: практикум по работе с формами
→ Часть 26: архитектура приложений, паттерн Container/Component
→ Часть 27: курсовой проект
Занятие 19. Свойства компонентов в React
→ Оригинал
Создадим новый проект средствами create-react-app
и изменим код нескольких стандартных файлов из папки src
.
Вот код файла index.js
:
import React from "react"
import ReactDOM from "react-dom"
import "./index.css"
import App from "./App"
ReactDOM.render(<App />, document.getElementById("root"))
Вот стили, которые описаны в файле index.css
:
body {
margin: 0;
}
.contacts {
display: flex;
flex-wrap: wrap;
}
.contact-card {
flex-basis: 250px;
margin: 20px;
}
.contact-card > img {
width: 100%;
height: auto;
}
.contact-card > h4 {
text-align: center;
}
.contact-card > p {
font-size: 12px;
}
Вот код, находящийся в файле App.js
:
import React from "react"
function App() {
return (
<div className="contacts">
<div className="contact-card">
<img align="center" src="http://placekitten.com/300/200"/>
<h4><font color="#3AC1EF">▍Mr. Whiskerson</font></h4>
<p>Phone: (212) 555-1234</p>
<p>Email: [email protected]</p>
</div>
<div className="contact-card">
<img align="center" src="http://placekitten.com/400/200"/>
<h4><font color="#3AC1EF">▍Fluffykins</font></h4>
<p>Phone: (212) 555-2345</p>
<p>Email: [email protected]</p>
</div>
<div className="contact-card">
<img align="center" src="http://placekitten.com/400/300"/>
<h4><font color="#3AC1EF">▍Destroyer</font></h4>
<p>Phone: (212) 555-3456</p>
<p>Email: [email protected]</p>
</div>
<div className="contact-card">
<img align="center" src="http://placekitten.com/200/100"/>
<h4><font color="#3AC1EF">▍Felix</font></h4>
<p>Phone: (212) 555-4567</p>
<p>Email: [email protected]</p>
</div>
</div>
)
}
export default App
Вот как будет выглядеть это приложение в браузере.
Страница приложения в браузере
Проанализировав код и внешний вид приложения можно прийти к выводу о том, что для вывода карточек со сведениями о животных хорошо было бы использовать особые компоненты. Сейчас эти элементы формируются средствами компонента App
. Учитывая же то, о чём мы говорили на предыдущих занятиях, можно пойти и дальше — подумать об универсальном компоненте, который можно настраивать, передавая ему атрибуты или свойства.
В нашем приложении имеются карточки с изображениями кошек, их именами и контактными сведениями их владельцев (а может — и их самих) — телефоном и адресом электронной почты. Для того чтобы создать компонент, который в дальнейшем станет основой для всех подобных карточек, можно взять один из фрагментов разметки, возвращаемой компонентом App
. Например — такой:
<div className="contact-card">
<img align="center" src="http://placekitten.com/300/200"/>
<h4><font color="#3AC1EF">▍Mr. Whiskerson</font></h4>
<p>Phone: (212) 555-1234</p>
<p>Email: [email protected]</p>
</div>
App возвращает четыре подобных блока, каждый из них можно было бы использовать для создания самостоятельного компонента, но такой подход нас не устраивает. Поэтому создадим один компонент, который станет основой всех карточек, выводимых приложением. Для этого создадим в папке src
новый файл компонента — ContactCard.js
и поместим в него код, который возвращает первый элемент <div>
, возвращаемый компонентом App
, код которого приведён выше. Вот каким будет код компонента ContactCard
:
import React from "react"
function ContactCard() {
return (
<div className="contact-card">
<img align="center" src="http://placekitten.com/300/200"/>
<h4><font color="#3AC1EF">▍Mr. Whiskerson</font></h4>
<p>Phone: (212) 555-1234</p>
<p>Email: [email protected]</p>
</div>
)
}
export default ContactCard
Ясно, что если создать несколько экземпляров этого компонента, то все они будут содержать одни и те же данные, так как эти данные жёстко заданы в коде компонента. А нам хотелось бы, чтобы, при создании разных экземпляров этого компонента, можно было бы настраивать выводимые им данные. Речь идёт о том, чтобы компоненту можно было бы передавать некие свойства, которыми он потом сможет воспользоваться.
Мы работаем с функциональными компонентами, которые представляют собой обычные JS-функции, в которых, благодаря использованию библиотеки React, можно использовать особые конструкции. Как известно, функции могут принимать аргументы, хотя их можно использовать и без аргументов. Аналогией нашего компонента ContactCard
, в том виде, в котором он сейчас существует, может стать такая вот простая функция, которая, ничего не принимая, просто возвращает сумму двух чисел:
function addNumbers() {
return 1 + 1
}
Её можно использовать для того, чтобы узнать сумму чисел 1 и 1, но, например, для того, чтобы сложить 1 и 2, используя функции, которые не принимают никаких входных данных, нам пришлось бы писать новую функцию. Совершенно очевидно то, что такой подход приведёт к огромным неудобствам при необходимости сложения разных чисел, поэтому в подобной ситуации будет разумным создать универсальную функцию для сложения чисел, которая принимает два числа и возвращает их сумму:
function addNumbers(a, b) {
return a + b
}
То, что возвращает такая функция, будет зависеть от того, какие аргументы ей передали при вызове. Создавая React-компоненты мы можем пойти точно таким же путём.
Импортируем в файл App.js
компонент ContactCard
и вернём четыре его экземпляра, не удаляя пока код, который формирует карточки на странице приложения:
import React from "react"
import ContactCard from "./ContactCard"
function App() {
return (
<div className="contacts">
<ContactCard />
<ContactCard />
<ContactCard />
<ContactCard />
<div className="contact-card">
<img align="center" src="http://placekitten.com/300/200"/>
<h4><font color="#3AC1EF">▍Mr. Whiskerson</font></h4>
<p>Phone: (212) 555-1234</p>
<p>Email: [email protected]</p>
</div>
<div className="contact-card">
<img align="center" src="http://placekitten.com/400/200"/>
<h4><font color="#3AC1EF">▍Fluffykins</font></h4>
<p>Phone: (212) 555-2345</p>
<p>Email: [email protected]</p>
</div>
<div className="contact-card">
<img align="center" src="http://placekitten.com/400/300"/>
<h4><font color="#3AC1EF">▍Destroyer</font></h4>
<p>Phone: (212) 555-3456</p>
<p>Email: [email protected]</p>
</div>
<div className="contact-card">
<img align="center" src="http://placekitten.com/200/100"/>
<h4><font color="#3AC1EF">▍Felix</font></h4>
<p>Phone: (212) 555-4567</p>
<p>Email: [email protected]</p>
</div>
</div>
)
}
export default App
Теперь поработаем над кодом, используемым для создания экземпляров компонента ContactCard
. Создавая обычные HTML-элементы, мы можем настраивать их атрибуты, влияющие на их поведение и внешний вид. Имена этих атрибутов жёстко заданы стандартом. В случае с компонентами можно воспользоваться точно таким же подходом, с той только разницей, что имена атрибутов мы придумываем сами, и сами же решаем — как именно они будут использованы в коде компонента.
Каждая из карточек содержит четыре фрагмента информации, которые, от карточки к карточке, могут меняться. Это — изображение кошки и её имя, а также телефон и адрес электронной почты. Пусть имя кошки будет содержаться в свойстве name
, адрес изображения — в свойстве imgURL
, телефон — в свойстве phone
, а адрес электронной почты — в свойстве email
.
Зададим эти свойства экземплярам компонентов ContactCard
и, по мере переноса данных из кода, который уже имеется в App
, будем удалять соответствующие его фрагменты. В результате код компонента App
будет выглядеть так:
import React from "react"
import ContactCard from "./ContactCard"
function App() {
return (
<div className="contacts">
<ContactCard
name="Mr. Whiskerson"
imgUrl="http://placekitten.com/300/200"
phone="(212) 555-1234"
email="[email protected]"
/>
<ContactCard
name="Fluffykins"
imgUrl="http://placekitten.com/400/200"
phone="(212) 555-2345"
email="[email protected]"
/>
<ContactCard
name="Destroyer"
imgUrl="http://placekitten.com/400/300"
phone="(212) 555-3456"
email="[email protected]"
/>
<ContactCard
name="Felix"
imgUrl="http://placekitten.com/200/100"
phone="(212) 555-4567"
email="[email protected]"
/>
</div>
)
}
export default App
Правда, одной только передачи свойств компоненту недостаточно для того, чтобы они были бы в нём использованы. Страница, которая будет сформирована вышеприведённым компонентом App
, будет содержать четыре одинаковых карточки, данные которых заданы в коде компонента ContactCard
, который пока не знает о том, что ему делать с переданными ему свойствами.
Данные карточек жёстко заданы в коде, компонент не умеет работать с переданными ему свойствами
Поэтому сейчас пришло время поговорить о том, как компонент ContactCard
может работать со свойствами, передаваемыми ему при создании его экземпляров.
Приступим к решению этой задачи, указав, при объявлении функции ContactCard
, что она принимает параметр props
. При этом код компонента будет выглядеть так:
import React from "react"
function ContactCard(props) {
return (
<div className="contact-card">
<img align="center" src="http://placekitten.com/300/200"/>
<h4><font color="#3AC1EF">▍Mr. Whiskerson</font></h4>
<p>Phone: (212) 555-1234</p>
<p>Email: [email protected]</p>
</div>
)
}
export default ContactCard
На самом деле, этот параметр можно назвать как угодно, но в React принято называть его именно props
, и те свойства, о которых мы тут говорим, часто называют просто «props».
Параметр props
— это объект. Свойствами этого объекта являются свойства, переданные компоненту при создании его экземпляра. То есть, например, в нашем объекте props
будет свойство props.name
, содержащее имя кошки, переданное компоненту при создании его экземпляра. Кроме того, у него будут свойства props.imgUrl
, props.phone
, props.email
. Для того чтобы в этом убедиться, добавим в начало функции ContactCard
команду console.log(props)
.
import React from "react"
function ContactCard(props) {
console.log(props)
return (
<div className="contact-card">
<img align="center" src="http://placekitten.com/300/200"/>
<h4><font color="#3AC1EF">▍Mr. Whiskerson</font></h4>
<p>Phone: (212) 555-1234</p>
<p>Email: [email protected]</p>
</div>
)
}
export default ContactCard
Это позволит вывести объект props
, получаемый компонентом, в консоль.
Объект props в консоли
Тут можно видеть вывод четырёх объектов из ContactCard.js
. Их именно столько из-за того, что мы создаём четыре экземпляра компонента ContactCard
.
Всё это даёт нам возможность использовать в коде компонента, вместо жёстко заданных значений, то, что передано ему при создании его экземпляра, доступное в виде свойств объекта props
.
Что если мы попытаемся воспользоваться свойством props.imgUrl
так:
<img align="center" src=props.imgUrl/>
На первый взгляд такая конструкция может сработать, но вспомним о том, что тут нам нужно использовать сущность из JavaScript в JSX-коде. О том, как это делается, мы говорили на одном из предыдущих занятий. А именно, в нашем случае свойство объекта нужно заключить в фигурные скобки:
<img align="center" src={props.imgUrl}/>
Переработаем по такому же принципу другие элементы, возвращаемые компонентом, после чего его код примет следующий вид:
import React from "react"
function ContactCard(props) {
return (
<div className="contact-card">
<img align="center" src={props.imgUrl}/>
<h4><font color="#3AC1EF">▍{props.name}</font></h4>
<p>Phone: {props.phone}</p>
<p>Email: {props.email}</p>
</div>
)
}
export default ContactCard
Обратите внимание на то, что в полях для вывода телефона и адреса электронной почты мы оставили тексты Phone:
и Email:
с пробелами, следующими за ними, так как эти тексты используются во всех компонентах. Если теперь взглянуть на страницу приложения, то можно заметить, что она содержит четыре разных карточки.
Страница, сформированная с использованием универсального компонента
Наш компонент принимает всего четыре свойства. Что если некоему компоненту нужно будет, например, передать 50 свойств? Пожалуй, передавать каждое такое свойство отдельной строкой, как это сделано в компоненте App
, будет неудобно. В таких случаях можно воспользоваться другим способом передачи свойств компонентам. Он заключается в том, что, при создании экземпляра компонента, ему передаётся не список свойств, а объект со свойствами. Вот как это может выглядеть на примере первого компонента:
import React from "react"
import ContactCard from "./ContactCard"
function App() {
return (
<div className="contacts">
<ContactCard
contact={{
name: "Mr. Whiskerson",
imgUrl: "http://placekitten.com/300/200",
phone: "(212) 555-1234",
email: "[email protected]"
}}
/>
<ContactCard
name="Fluffykins"
imgUrl="http://placekitten.com/400/200"
phone="(212) 555-2345"
email="[email protected]"
/>
<ContactCard
name="Destroyer"
imgUrl="http://placekitten.com/400/300"
phone="(212) 555-3456"
email="[email protected]"
/>
<ContactCard
name="Felix"
imgUrl="http://placekitten.com/200/100"
phone="(212) 555-4567"
email="[email protected]"
/>
</div>
)
}
export default App
Нельзя сказать, что этот подход значительно сократил количество кода, используемого для описания экземпляра компонента. Дело в том, что свойства, передаваемые компоненту, всё так же жёстко заданы в коде, хотя мы и передаём компоненту лишь один объект. Преимущества этого подхода можно будет ощутить в ситуациях, когда данные для компонента получают из неких внешних источников. Например — из JSON-файла.
В ходе модификации кода компонента App
, используемого для создания первого экземпляра компонента ContactCard
, правильная работа приложения была нарушена. Вот как теперь будет выглядеть его страница.
Нарушение правильной работы приложения
Как это можно это исправить? Для того чтобы в этом разобраться, полезно будет проанализировать происходящее с помощью команды console.log(props)
.
Анализ объекта props
Как видно, объект props
первого компонента отличается от такого же объекта второго и следующих компонентов.
В компоненте ContactCard
мы пользуемся объектом props
исходя из предположения о том, что у него есть свойства name
, imgUrl
и прочие подобные. Здесь же первый компонент получает лишь одно свойство — contact
. Это приводит к тому, что у объекта props
оказывается лишь одно свойство — contact
, являющееся объектом, а в коде компонента работа с подобной структурой не предусмотрена.
Перевести наш компонент на модель использования лишь одного свойства-объекта contact
, содержащего другие свойства, довольно просто. Для этого, например, для доступа к свойству name
, достаточно воспользоваться конструкцией вида props.contact.name
в коде компонента. Аналогичные конструкции позволяют правильно работать с другими нужными нам свойствами.
Переработаем код компонента с учётом передачи ему единственного свойства-объекта contact
, содержащего другие свойства:
import React from "react"
function ContactCard(props) {
console.log(props)
return (
<div className="contact-card">
<img align="center" src={props.contact.imgUrl}/>
<h4><font color="#3AC1EF">▍{props.contact.name}</font></h4>
<p>Phone: {props.contact.phone}</p>
<p>Email: {props.contact.email}</p>
</div>
)
}
export default ContactCard
Первый компонент теперь должен будет выводиться нормально, но мы этого, на данном этапе работы над проектом, не увидим, так как система сообщит нам о множестве ошибок, связанных с тем, что несколько экземпляров компонента ContactCard
, создаваемые в компоненте App
, не получают свойство-объект contact
. При выполнении кода это свойство будет иметь значение undefined
. В результате производится попытка обратиться к некоему свойству значения undefined
, что и приводит к возникновению ошибки. Исправим это, переработав код компонента App
, ответственный за формирование компонентов ContactCard
:
import React from "react"
import ContactCard from "./ContactCard"
function App() {
return (
<div className="contacts">
<ContactCard
contact={{
name: "Mr. Whiskerson",
imgUrl: "http://placekitten.com/300/200",
phone: "(212) 555-1234",
email: "[email protected]"
}}
/>
<ContactCard
contact={{
name: "Fluffykins",
imgUrl: "http://placekitten.com/400/200",
phone: "(212) 555-2345",
email: "[email protected]"
}}
/>
<ContactCard
contact={{
name: "Destroyer",
imgUrl: "http://placekitten.com/400/300",
phone: "(212) 555-3456",
email: "[email protected]"
}}
/>
<ContactCard
contact={{
name: "Felix",
imgUrl: "http://placekitten.com/200/100",
phone: "(212) 555-4567",
email: "[email protected]"
}}
/>
</div>
)
}
export default App
Теперь страница приложения будет выглядеть так же, как раньше.
Как обычно, рекомендуется самостоятельно поэкспериментировать с изученными сегодня концепциями для того, чтобы лучше их усвоить. Например — можете поработать с кодом, добавить новые свойства, передаваемые компоненту, и попытаться использовать их в компоненте.
Итоги
Сегодня мы познакомились с концепцией свойств, которые можно передавать компонентам React для того, чтобы управлять их поведением и внешним видом. Эти свойства напоминают атрибуты HTML-элементов, но, пользуясь свойствами в компонентах, программист самостоятельно принимает решение о том, какой смысл они несут и что именно делать с ними в компоненте. В следующий раз вас будет ждать практическое занятие по работе со свойствами компонентов и по стилизации.
Уважаемые читатели! Как вы экспериментировали с кодом сегодняшнего примера для того, чтобы лучше разобраться со свойствами React-компонентов?
Учебный курс по React, часть 2: функциональные компоненты
Учебный курс по React, часть 2: функциональные компоненты
Cегодня мы представляем вашему внимание продолжение курса. Здесь мы поговорим о функциональных компонентах.
→ Часть 1: обзор курса, причины популярности React, ReactDOM и JSX
Занятие 6. Функциональные компоненты
На предыдущем практическом занятии мы говорили о том, что необязательно размещать весь JSX-код, формирующий HTML-элементы, в аргументе метода ReactDOM.render()
. В нашем случае речь идёт о маркированном списке, таком, описание которого представлено ниже.
import React from "react"
import ReactDOM from "react-dom"
ReactDOM.render(
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>,
document.getElementById("root")
)
Представьте себе, что надо вывести, пользуясь таким же подходом, целую веб-страницу, на которой имеются сотни элементов. Если это сделать, то нормально поддерживать такой код будет практически невозможно. Когда мы говорили о причинах популярности React, одной из них была поддержка этой библиотекой компонентов, подходящих для повторного использования. Сейчас мы поговорим о том, как создавать функциональные компоненты React.
Эти компоненты называются «функциональными» из-за того, что создают их, конструируя особые функции.
Создадим новую функцию и дадим ей имя MyApp
:
import React from "react"
import ReactDOM from "react-dom"
function MyApp() {
}
ReactDOM.render(
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>,
document.getElementById("root")
)
Имя функции сделано именно таки по той причине, что здесь используется схема именования функций-конструкторов. Их имена (фактически — имена компонентов) записываются в верблюжьем стиле — первые буквы слов, из которых они состоят, делаются заглавными, в том числе — первая буква первого слова. Вам следует строго придерживаться этого соглашения об именовании подобных функций.
Функциональные компоненты устроены довольно просто. А именно, в теле функции должна быть команда, возвращающая JSX-код, который и представляет соответствующий компонент.
В нашем примере достаточно взять код маркированного списка и организовать возврат этого кода из функционального компонента. Вот как это может выглядеть:
function MyApp() {
return <ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
}
И хотя в данном случае всё будет работать так, как ожидается, то есть, команда return
вернёт весь этот код, рекомендуется заключать подобные конструкции в круглые скобки и применять ещё одно соглашение, принятое в React при форматировании кода программ. Оно заключается в том, что отдельные элементы помещают на отдельных строках и соответствующим образом выравнивают. В результате применения вышеописанных идей код нашего функционального компонента будет выглядеть так:
function MyApp() {
return (
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
)
}
При таком подходе возвращаемая из компонента разметка оказывается очень похожей на обычный HTML-код.
Теперь, в методе ReactDOM.render()
, можно создать экземпляр нашего функционального компонента, передав его этому методу в качестве первого аргумента и заключив его в JSX-тег.
import React from "react"
import ReactDOM from "react-dom"
function MyApp() {
return (
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
)
}
ReactDOM.render(
<MyApp />,
document.getElementById("root")
)
Можно заметить, что тут использован самозакрывающийся тег. В некоторых случаях, когда нужно создавать компоненты, имеющие более сложную структуру, подобные конструкции строятся иначе, но пока мы будем пользоваться именно такими самозакрывающимися тегами.
Если обновить страницу, сформированную средствами вышеприведённого кода, то её внешний вид будет таким же, каким он был до выноса разметки маркированного списка в функциональный компонент.
Разметка, которую возвращают функциональные компоненты, подчиняется тем же правилам, которые мы рассматривали в применении к первому параметру метода ReactDOM.render()
. То есть — нельзя, чтобы в ней присутствовали JSX-элементы, следующие друг за другом. Попытка поместить в предыдущем примере после элемента <ul>
любой другой элемент, скажем — <ol>
, приведёт к ошибке. Избежать этой проблемы можно, например, просто обернув всё, что возвращает функциональный компонент, в элемент <div>
.
Возможно, вы уже начали ощущать то, какие мощные возможности даёт нам использование функциональных компонентов. В частности, речь идёт о создании собственных компонентов, которые содержат фрагменты JSX-кода, представляющие собой описание HTML-разметки, которая окажется на веб-странице. Такие компоненты можно компоновать друг с другом.
В нашем примере имеется компонент, выводящий простой HTML-список, но, по мере того, как мы будем создавать всё более сложные приложения, мы будем разрабатывать компоненты, выводящие другие созданные нами компоненты. В итоге всё это будет превращаться в обычные HTML-элементы, но иногда для формирования этих элементов понадобятся, возможно, десятки собственных компонентов.
В итоге, когда мы будем создавать всё больше компонентов, мы будем размещать их в отдельных файлах, но пока вам важно освоить то, что мы только что обсудили, привыкнуть к функциональным компонентам. В процессе прохождения курса вы будете создавать всё более и более сложные файловые структуры.
На этом занятии мы разобрали основы функциональных компонентов, а на следующем применим полученные знания на практике.
Занятие 7. Практикум. Функциональные компоненты
▍Задание
-
Подготовьте базовый React-проект.
-
Создайте функциональный компонент
MyInfo
, формирующий следующие HTML-элементы: -
Выведите экземпляр компонента
MyInfo
на веб-страницу.O
▍Дополнительное задание
Стилизуйте элементы страницы, самостоятельно узнав о том, как это сделать (поищите в Google). Надо отметить, что о стилизации компонентов мы в этом курсе ещё поговорим.
Примечание: сворачиваемый блок
▍Решение
Тут нас устроит такая же HTML-страница, которой мы пользовались ранее. Файл с React-кодом тоже будет выглядеть вполне стандартно. А именно, импортируем в него библиотеки, создадим каркас функционального компонента MyInfo
и вызовем метод render()
объекта ReactDOM
, передав ему компонент, который надо вывести на страницу, и ссылку на элемент страницы, в котором должен быть выведен этот компонент. На данном этапе работы код будет выглядеть так:
import React from "react"
import ReactDOM from "react-dom"
function MyInfo() {
}
ReactDOM.render(<MyInfo />, document.getElementById("root"))
Теперь нужно вернуть из MyInfo
JSX-код, формирующий HTML-разметку в соответствии с заданием. Вот полный код решения.
import React from "react"
import ReactDOM from "react-dom"
function MyInfo() {
return (
<div>
<h2>Bob Ziroll</h2>
<p>This is a paragraph about me...</p>
<ul>
<li>Thailand</li>
<li>Japan</li>
<li>Nordic Countries</li>
</ul>
</div>
)
}
ReactDOM.render(
<MyInfo />,
document.getElementById("root")
)
Обратите внимание на то, что конструкция, возвращаемая из MyInfo
, заключена в круглые скобки, и на то, что элементы, которые нужно вывести, находятся внутри вспомогательного элемента <div>
.
Итоги
В этом материале мы познакомились с функциональными компонентами React. В следующий раз поговорим о файлах компонентов и о структуре React-проектов.
компоненты, основанные на классах / Блог компании RUVDS.com / Хабр
Сегодня мы публикуем перевод очередного занятия учебного курса по React. Оно посвящено компонентам, основанным на классах. Такие компоненты создают с использованием ключевого слова class.
→ Часть 1: обзор курса, причины популярности React, ReactDOM и JSX
→ Часть 2: функциональные компоненты
→ Часть 3: файлы компонентов, структура проектов
→ Часть 4: родительские и дочерние компоненты
→ Часть 5: начало работы над TODO-приложением, основы стилизации
→ Часть 6: о некоторых особенностях курса, JSX и JavaScript
→ Часть 7: встроенные стили
→ Часть 8: продолжение работы над TODO-приложением, знакомство со свойствами компонентов
→ Часть 9: свойства компонентов
→ Часть 10: практикум по работе со свойствами компонентов и стилизации
→ Часть 11: динамическое формирование разметки и метод массивов map
→ Часть 12: практикум, третий этап работы над TODO-приложением
→ Часть 13: компоненты, основанные на классах
→ Часть 14: практикум по компонентам, основанным на классах, состояние компонентов
→ Часть 15: практикумы по работе с состоянием компонентов
→ Часть 16: четвёртый этап работы над TODO-приложением, обработка событий
→ Часть 17: пятый этап работы над TODO-приложением, модификация состояния компонентов
→ Часть 18: шестой этап работы над TODO-приложением
→ Часть 19: методы жизненного цикла компонентов
→ Часть 20: первое занятие по условному рендерингу
→ Часть 21: второе занятие и практикум по условному рендерингу
→ Часть 22: седьмой этап работы над TODO-приложением, загрузка данных из внешних источников
→ Часть 23: первое занятие по работе с формами
→ Часть 24: второе занятие по работе с формами
→ Часть 25: практикум по работе с формами
→ Часть 26: архитектура приложений, паттерн Container/Component
→ Часть 27: курсовой проект
Занятие 24. Компоненты, основанные на классах
→ Оригинал
Если вы, до того, как начали осваивать этот учебный курс, изучали React по материалам каких-то других курсов, у вас может возникнуть вопрос по поводу того, что здесь мы пользуемся функциональными компонентами. Дело в том, что во многих других курсах эта тема либо не освещается, либо о функциональных компонентах говорят как о чём-то таком, в чём нет особой необходимости. Некоторые авторы идут ещё дальше и говорят о том, что функциональные компоненты лучше не использовать, отдавая предпочтение компонентам, основанным на классах. Это, по их мнению, избавляет программиста от ненужной нагрузки. Я же полагаю, что любому, кто изучает React, полезно будет увидеть полную картину и узнать о популярных в наши дни подходах по работе с компонентами. В частности, сейчас актуально направление, в соответствии с которым везде, где это возможно, используют функциональные компоненты, а компоненты, основанные на классах — лишь там, где они действительно необходимы. При этом надо отметить, что всё это — лишь рекомендации. Каждый разработчик сам решает как именно он будет конструировать свои приложения.
Когда я веду курсы по React, я предпочитаю начинать с функциональных компонентов, так как функции — понятные конструкции. Одного взгляда на функциональный компонент достаточно для того, чтобы понять, какие именно действия он выполняет. Скажем, вот код функционального компонента, который представляет собой обычную функцию, возвращающую элемент <div>
, содержащий элемент <h2>
с неким текстом.
function App() {
return (
<div>
<h2>Code goes here</h2>
</div>
)
}
Но, по мере того, как мы углубляемся в изучение React, знакомимся с его возможностями, оказывается, что функциональные компоненты не способны предложить нам всё то, что может понадобиться нам от React-компонентов. Поэтому сегодня мы поговорим о компонентах, основанных на классах. А именно, начнём с создания компонента, основанного на классе, который выполняет те же действия, что и вышеприведённый функциональный компонент. А на следующих занятиях мы коснёмся тех дополнительных возможностей, которые дают нам компоненты, основанные на классах. В частности, речь идёт о возможности работы с состоянием компонентов и с методами их жизненного цикла.
Преобразуем функциональный компонент в компонент, основанный на классе. Если вы не особенно хорошо знакомы с ключевым словом class
, появившемся в ES6, и с возможностями, которые оно открывает перед разработчиками, рекомендуется уделить некоторое время на то, чтобы познакомиться с классами поближе.
Описание компонента, основанного на классах, начинается с ключевого слова class
. Затем идёт имя компонента, составляемое по тем же правилам, что и имена функциональных компонентов. При этом после конструкции наподобие class App
будет идти не нечто вроде фигурной скобки, а конструкция вида extends React.Component
. После неё ставится пара фигурных скобок, в которых будет описано тело класса.
Классы в JavaScript представляют собой надстройку над традиционной моделью прототипного наследования. Сущность конструкции class App extends React.Component
сводится к тому, что мы объявляем новый класс и указываем на то, что его прототипом должен быть React.Component
. Наличие у нашего компонента этого прототипа позволяет пользоваться в этом компоненте всеми теми полезными возможностями, которые имеются в React.Component
.
Итак, на данном этапе работы над компонентом, основанном на классах, его код выглядит так:
class App extends React.Component {
}
У компонента, основанного на классах, должен быть, по меньшей мере, один метод. Это — метод render()
. Данный метод должен возвращать то же самое, что мы обычно возвращаем из функциональных компонентов. Вот как выглядит полный код компонента, основанного на классах, реализующего те же возможности, что и вышеприведённый функциональный компонент.
class App extends React.Component {
render() {
return (
<div>
<h2>Code goes here</h2>
</div>
)
}
}
Работают с компонентами, основанными на классах так же, как с функциональными компонентами. То есть, в нашем случае достаточно заменить код функционального компонента на новый код и приложение будет работать так же, как и прежде.
Поговорим о методе render()
. Если, перед формированием элементов, возвращаемых этим методом, нужно выполнить некие вычисления, их выполняют именно в этом методе, перед командой return
. То есть, если у вас есть некий код, определяющий порядок формирования визуального представления компонента, этот код нужно поместить в метод render
. Например, тут можно выполнить настройку стилей в том случае, если вы пользуетесь встроенными стилями. Здесь же будет и код, реализующий механизм условного рендеринга, и другие подобные конструкции.
Если вы знакомы с классами, вы можете создать собственный метод и разместить код, готовящий компонент к визуализации, в нём, после чего вызвать этот метод в методе render
. Выглядит это так:
class App extends React.Component {
yourMethodHere() {
}
render() {
const style = this.yourMethodHere()
return (
<div>
<h2>Code goes here</h2>
</div>
)
}
}
А именно, тут мы исходим из предположения о том, что в методе yourMethodHere()
производится формирование стилей, а то, что он возвращает, записывается в константу style
, объявленную в методе render()
. Обратите внимание на то, что для обращения к нашему собственному методу используется ключевое слово this
. Позже мы поговорим об особенностях этого ключевого слова, но пока остановимся на представленной здесь конструкции.
Теперь поговорим о том, как в компонентах, основанных на классах, работать со свойствами, передаваемыми им при создании их экземпляров.
При использовании функциональных компонентов мы объявляли соответствующую функцию с параметром props
, представляющим собой объект, в который попадало то, что передавалось компоненту при создании его экземпляра. Выглядит это так:
function App(props) {
return (
<div>
<h2>{props.whatever}</h2>
</div>
)
}
При работе с компонентом, основанном на классе, то же самое выглядит так:
class App extends React.Component {
render() {
return (
<div>
<h2>{this.props.whatever}</h2>
</div>
)
}
}
Итоги
Как уже было сказано, компоненты, основанные на классах, дают разработчику множество возможностей. Об этих возможностях мы ещё поговорим. А сейчас можете поэкспериментировать с тем, что вы узнали сегодня и подготовиться к практическому занятию по компонентам, которые основаны на классах.
Уважаемые читатели! Если вы профессионально используете React — просим рассказать о том, в каких ситуациях вы используете функциональные компоненты, а в каких — компоненты, основанные на классах.
Наши лучшие практики написания компонентов React
Наши лучшие практики написания компонентов React
Я помню, когда я только начинал писать на React, я видел много разных подходов к построению компонентов, сильно различающихся от учебника до учебника. И хотя с тех пор фреймворк значительно созрел, похоже, до сих пор не существует единственного «правильного» способа написания компонентов.
За последний год в MuseFind наша команда написала много компонентов React. Мы постепенно улучшаем наш подход, пока он не будет полностью нас устраивать.
В этом руководстве я собрал наши лучшие практики. Мы надеемся, что это будет полезно, будь вы новичок или опытный.
Прежде чем мы начнем, несколько замечаний:
- Мы используем синтаксис ES6 и ES7.
- Если вы не уверены в том, чем отличаются презентационные компоненты и компоненты контейнеры, прочтите это.
- Пожалуйста, дайте нам знать в комментариях, если у вас есть предложения, вопросы или обратная связь.
Компоненты на основе классов
Компоненты на основе классов имеют состояние и/или содержат методы. Мы стараемся использовать их как можно реже, но и для них находится свое применение.
Давайте пошагово построим наш компонент, строка за строкой.
Импорт CSS
import React, {Component} from ‘react’
import {observer} from ‘mobx-react’
import ExpandableForm from ‘./ExpandableForm’
import ‘./styles/ProfileContainer.css’
| import React, {Component} from ‘react’ import {observer} from ‘mobx-react’
import ExpandableForm from ‘./ExpandableForm’ import ‘./styles/ProfileContainer.css’ |
Мне нравится CSS в JavaScript, в теории. Но это все еще новая идея, и зрелое решение не появилось. До тех пор мы импортируем файл CSS для каждого компонента.
Мы также отделяем импорт зависимостей от локального импорта пустой строкой.
Инициализация состояния
import React, {Component} from ‘react’
import {observer} from ‘mobx-react’
import ExpandableForm from ‘./ExpandableForm’
import ‘./styles/ProfileContainer.css’
export default class ProfileContainer extends Component {
state = { expanded: false }
| import React, {Component} from ‘react’ import {observer} from ‘mobx-react’
import ExpandableForm from ‘./ExpandableForm’ import ‘./styles/ProfileContainer.css’
export default class ProfileContainer extends Component { state = { expanded: false } |
Вы также можете использовать более старый подход к инициализации состояния в конструкторе. Подробнее об этом здесь. Мы предпочитаем более чистый путь.
Мы также обязательно экспортируем наш класс по умолчанию.
propTypes and defaultProps
import React, {Component} from ‘react’
import {observer} from ‘mobx-react’
import ExpandableForm from ‘./ExpandableForm’
import ‘./styles/ProfileContainer.css’
export default class ProfileContainer extends Component {
state = { expanded: false }
static propTypes = {
model: React.PropTypes.object.isRequired,
title: React.PropTypes.string
}
static defaultProps = {
model: {
id: 0
},
title: ‘Your Name’
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import React, {Component} from ‘react’ import {observer} from ‘mobx-react’
import ExpandableForm from ‘./ExpandableForm’ import ‘./styles/ProfileContainer.css’
export default class ProfileContainer extends Component { state = { expanded: false }
static propTypes = { model: React.PropTypes.object.isRequired, title: React.PropTypes.string }
static defaultProps = { model: { id: 0 }, title: ‘Your Name’ } |
propTypes и defaultProps — статические свойства, которые описываются максимально высоко в коде компонента. Они должны быть сразу видны при чтении файла, поскольку представляют собой своего рода документацию.
Все компоненты должны иметь propTypes.
Методы
import React, {Component} from ‘react’
import {observer} from ‘mobx-react’
import ExpandableForm from ‘./ExpandableForm’
import ‘./styles/ProfileContainer.css’
export default class ProfileContainer extends Component {
state = { expanded: false }
static propTypes = {
model: React.PropTypes.object.isRequired,
title: React.PropTypes.string
}
static defaultProps = {
model: {
id: 0
},
title: ‘Your Name’
}
handleSubmit = (e) => {
e.preventDefault()
this.props.model.save()
}
handleNameChange = (e) => {
this.props.model.changeName(e.target.value)
}
handleExpand = (e) => {
e.preventDefault()
this.setState({ expanded: !this.state.expanded })
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| import React, {Component} from ‘react’ import {observer} from ‘mobx-react’
import ExpandableForm from ‘./ExpandableForm’ import ‘./styles/ProfileContainer.css’
export default class ProfileContainer extends Component { state = { expanded: false }
static propTypes = { model: React.PropTypes.object.isRequired, title: React.PropTypes.string }
static defaultProps = { model: { id: 0 }, title: ‘Your Name’ }
handleSubmit = |
файлы компонентов, структура проектов / Блог компании RUVDS.com / Хабр
В этом материале мы поговорим о файлах компонентов и о структуре React-проектов.
→ Часть 1: обзор курса, причины популярности React, ReactDOM и JSX
→ Часть 2: функциональные компоненты
→ Часть 3: файлы компонентов, структура проектов
→ Часть 4: родительские и дочерние компоненты
→ Часть 5: начало работы над TODO-приложением, основы стилизации
→ Часть 6: о некоторых особенностях курса, JSX и JavaScript
→ Часть 7: встроенные стили
→ Часть 8: продолжение работы над TODO-приложением, знакомство со свойствами компонентов
→ Часть 9: свойства компонентов
→ Часть 10: практикум по работе со свойствами компонентов и стилизации
→ Часть 11: динамическое формирование разметки и метод массивов map
→ Часть 12: практикум, третий этап работы над TODO-приложением
→ Часть 13: компоненты, основанные на классах
→ Часть 14: практикум по компонентам, основанным на классах, состояние компонентов
→ Часть 15: практикумы по работе с состоянием компонентов
→ Часть 16: четвёртый этап работы над TODO-приложением, обработка событий
→ Часть 17: пятый этап работы над TODO-приложением, модификация состояния компонентов
→ Часть 18: шестой этап работы над TODO-приложением
→ Часть 19: методы жизненного цикла компонентов
→ Часть 20: первое занятие по условному рендерингу
→ Часть 21: второе занятие и практикум по условному рендерингу
→ Часть 22: седьмой этап работы над TODO-приложением, загрузка данных из внешних источников
→ Часть 23: первое занятие по работе с формами
→ Часть 24: второе занятие по работе с формами
→ Часть 25: практикум по работе с формами
→ Часть 26: архитектура приложений, паттерн Container/Component
→ Часть 27: курсовой проект
Занятие 8. Файлы компонентов, структура React-проектов
→ Оригинал
▍Файлы компонентов
Если предположить, что вы выполняли задание из предыдущего практического занятия, используя стандартный проект, созданный create-react-app
, то сейчас в нём задействован файл index.html
из папки public
, содержимое которого нас устраивает, и файл index.js
из папки src
, в котором мы пишем код. В частности, index.js
выглядит сейчас примерно так:
import React from "react"
import ReactDOM from "react-dom"
function MyInfo() {
return (
<div>
<h2>Bob Ziroll</h2>
<p>This is a paragraph about me...</p>
<ul>
<li>Thailand</li>
<li>Japan</li>
<li>Nordic Countries</li>
</ul>
</div>
)
}
ReactDOM.render(
<MyInfo />,
document.getElementById("root")
)
Обратите внимание на то, что код функционального компонента MyInfo
содержится именно в этом файле. Как вы помните, React позволяет создавать множество компонентов, в этом кроется одна из его сильных сторон. Понятно, что разместить код большого количества компонентов в одном файле, хотя и технически реализуемо, на практике означает большие неудобства. Поэтому код компонентов, даже небольших по объёму, обычно оформляют в виде отдельных файлов. Именно такому подходу и рекомендуется следовать при разработке React-приложений.
Файлам компонентов дают имена, соответствующие именам компонентов, код которых эти файлы хранят. Размещают их, в случае с create-react-app
, в той же папке src
, где расположен файл index.js
. При таком подходе файл с компонентом MyInfo
получит имя MyInfo.js
.
Создадим файл MyInfo.js
и перенесём в него код компонента MyInfo
, удалив его из index.js
.
На данном этапе работы index.js
будет выглядеть так:
import React from "react"
import ReactDOM from "react-dom"
ReactDOM.render(
<MyInfo />,
document.getElementById("root")
)
Код MyInfo.js
будет таким:
function MyInfo() {
return (
<div>
<h2>Bob Ziroll</h2>
<p>This is a paragraph about me...</p>
<ul>
<li>Thailand</li>
<li>Japan</li>
<li>Nordic Countries</li>
</ul>
</div>
)
}
Вот как всё это выглядит в VSCode.
Перенос кода компонента в новый файл
Код компонента из index.js
мы перенесли, но получившаяся у нас сейчас структура пока ещё неработоспособна.
Во-первых, вспомните — для чего в index.js
нужна команда import React from "react"
, даже с учётом того, что мы напрямую к React
здесь не обращаемся. Причина этого в том, что без импорта React
не будут работать механизмы этой библиотеки, в частности — JSX. Именно благодаря этой команде импорта мы могли, на предыдущих занятиях, передавать методу ReactDOM.render()
JSX-код и выводить HTML-разметку, создаваемую на его основе, на страницу. Всё это значит, что в файле MyInfo.js
нам тоже нужно импортировать React. Это — обычная практика для файлов компонентов.
Во-вторых, нам нужно сделать так, чтобы функцией MyInfo
из файла MyInfo.js
можно было бы воспользоваться в других файлах приложения. Её для этого нужно экспортировать. Тут используются возможности стандарта ES6. В результате обновлённый код MyInfo.js
принимает следующий вид:
import React from "react"
function MyInfo() {
return (
<div>
<h2>Bob Ziroll</h2>
<p>This is a paragraph about me...</p>
<ul>
<li>Thailand</li>
<li>Japan</li>
<li>Nordic Countries</li>
</ul>
</div>
)
}
export default MyInfo
Теперь поработаем над файлом index.js
. А именно, нам нужно, чтобы компонент MyInfo
был бы доступен в этом файле. Сделать его доступным в index.js
можно, импортировав его.
Что если попробовать записать команду импорта компонента по образцу команд импорта react
и react-dom
в index.js
? Например, внесём в файл такую команду импорта:
import MyInfo from "MyInfo.js" // неправильно
Система, увидев такую команду, в частности, опираясь на то, что в ней отсутствуют сведения об относительном пути к файлу, будет искать зависимость проекта — модуль с именем, заданным при вызове этой команды (вот как устанавливать зависимости в проекты, созданные средствами create-react-app
; эти зависимости потом можно импортировать в React-проекты так же, как была импортирована библиотека React). Такого модуля она не найдёт, в результате команда импорта не сработает. Поэтому команду импорта файла нужно переписать с указанием пути к нему. В данном случае нас устроит указание на текущую директорию (./
) и команда импорта приобретёт следующий вид:
import MyInfo from "./MyInfo.js" // правильно
Кроме того, если говорить о команде import
, важно учитывать, что она подразумевает то, что с её помощью импортируются JavaScript-файлы. То есть расширение .js
вполне можно убрать, и команда import
, приобретя вид, показанный ниже, не утратит работоспособности.
import MyInfo from "./MyInfo" // правильно
Обычно подобные команды импорта JS-файлов записывают именно так.
Вот полный код файла index.js
.
import React from "react"
import ReactDOM from "react-dom"
import MyInfo from "./MyInfo"
ReactDOM.render(
<MyInfo />,
document.getElementById("root")
)
▍Структура проекта
При росте размеров и сложности React-проектов очень важно поддерживать в хорошем состоянии их структуру. В нашем случае, хотя наш проект сейчас и невелик, можно, в папке src
, создать папку components
, предназначенную для хранения файлов с кодом компонентов.
Создадим такую папку и переместим в неё файл MyInfo.js
. После этого нужно будет отредактировать команду импорта этого файла в index.js
.
А именно, сейчас путь к MyInfo.js
указывает на то, что этот файл находится там же, где и index.js
, но на самом деле файл этот теперь находится в папке components
, находящейся в той же папке, что и index.js
. В результате относительный путь к нему в index.js
будет выглядеть так: ./components/MyInfo
. Вот каким будет обновлённый код index.js
:
import React from "react"
import ReactDOM from "react-dom"
import MyInfo from "./components/MyInfo"
ReactDOM.render(
<MyInfo />,
document.getElementById("root")
)
А вот как всё это выглядит в VSCode.
Папка для хранения компонентов и импорт компонента из этой папки в VSCode
На самом деле, одна папка components
, предназначенная для размещения кода всех компонентов — это пример чрезвычайно упрощённой структуры проекта. В реальных проектах, для обеспечения удобства работы с большим количеством сущностей, используются гораздо более сложные структуры папок. То, какими именно будут эти структуры, зависит от нужд проекта и от личных предпочтений программиста.
Рекомендуется поэкспериментировать со всем тем, о чём вы сегодня узнали. Например, можете попробовать переместить файл MyInfo.js
в какую-нибудь папку и посмотреть — что из этого выйдет, можно попытаться переименовать его, поменять в нём какой-то код. Когда в ходе подобных экспериментов правильная работа проекта будет нарушена — полезно будет разобраться в проблеме и снова привести проект в работоспособное состояние.
Итоги
На этом занятии мы поговорили об оформлении кода компонентов в виде отдельных файлов, об экспорте и импорте кода средствами ES6 и о структуре React-проектов. В следующий раз мы продолжим знакомиться с возможностями компонентов.
Уважаемые читатели! Просим опытных React-разработчиков поделиться с новичками идеями по поводу организации структуры проектов.
Функциональные компоненты React — RWieruch
Функциональные компоненты React — также известные как функциональные компоненты React — это статус-кво написания современных приложений React. В прошлом существовали различные типы компонентов React, но с появлением React Hooks стало возможным писать все приложение, используя только функции в качестве компонентов React.
Это подробное руководство покажет вам все о компонентах функций React — которые в основном представляют собой просто функций JavaScript, являющихся компонентами React , которые возвращают JSX (синтаксис React) — так что после прочтения этого руководства вы должны быть хорошо подготовлены к реализовать с ними современные приложения React.
Примечание. В React есть несколько синонимов для этого вида компонентов. Возможно, вы видели различные варианты, такие как «Реагировать только на компонент» или «Реагировать на компонент как на функцию».
Оглавление
Пример компонента функции React
Давайте начнем с простого примера функционального компонента в React, определенного как приложение, которое возвращает JSX:
import React from 'react';
function App () {
const welcome = 'Привет, функциональный компонент!';
возврат
{приветствие}
;}
экспорт приложения по умолчанию;
Это уже основной синтаксис компонента функции React.Определение компонента происходит с помощью только функции JavaScript, которая должна возвращать JSX — синтаксис React для определения сочетания HTML и JavaScript, тогда как JavaScript используется с фигурными скобками внутри HTML. В нашем случае мы визуализируем переменную с именем welcome , которая определена в теле функции компонента и возвращается как заголовок HTML в JSX.
Примечание. Если вы знакомы с компонентами класса React, вы могли заметить, что функциональный компонент — это компонент React без функции рендеринга.Все, что определено в теле функции, — это функция рендеринга, которая в конце возвращает JSX.
Теперь, если вы хотите визуализировать компонент React внутри функционального компонента, вы определяете другой компонент и визуализируете его как HTML-элемент с JSX в теле другого компонента:
import React from 'react';
function App () {
return
; }
function Headline () {
const welcome = 'Компонент функции Hello!';
возврат
{приветствие}
;}
экспорт приложения по умолчанию;
По сути, теперь у вас есть функция как дочерний компонент.Определение компонентов React и их рендеринг друг в друге делает возможным Composition in React. Вы можете решить, где визуализировать компонент и как его визуализировать.
Функциональный компонент React: props
Давайте узнаем о функциональном компоненте React с props. В React реквизиты используются для передачи информации от компонента к компоненту. Если вы не знаете о реквизитах в React, прочитайте статью по ссылке. По сути, свойства в React всегда передаются вниз по дереву компонентов:
import React from response;
function App () {
const welcome = 'Привет, функциональный компонент!';
return <значение заголовка = {приветствие} />;
}
function Заголовок (реквизиты) {
return
{props.значение}
;}
экспорт приложения по умолчанию;
Props — это параметры компонента React Function. В то время как компонент может оставаться универсальным, мы сами решаем извне, что он должен отображать (или как он должен себя вести). При рендеринге компонента (например, заголовка в компоненте приложения) вы можете передавать компоненту реквизиты как атрибуты HTML. Затем в функциональном компоненте объект props доступен как аргумент в сигнатуре функции.
Поскольку props всегда поступает как объект, и чаще всего вам все равно нужно извлекать информацию из props, деструктуризация объекта JavaScript пригодится.Вы можете напрямую использовать его в сигнатуре функции для объекта props:
import React from 'react';
function App () {
const welcome = 'Привет, функциональный компонент!';
return <значение заголовка = {приветствие} />;
}
function Заголовок ({значение}) {
return
{value}
;}
экспорт приложения по умолчанию;
Примечание. Если вы забыли о деструктуризации JavaScript и просто получили доступ к реквизитам из сигнатуры функции компонента, например
function Headline (value1, value2) {...}
, вы можете увидеть сообщения «props undefined». Это не работает, потому что свойства всегда доступны как первый аргумент функции и могут быть оттуда деструктурированы:function Headline ({value1, value2}) {...}
.Если вы хотите узнать больше трюков и советов о реквизитах React, еще раз ознакомьтесь со связанной статьей в начале этого раздела. Там вы узнаете о случаях, когда вы не хотите разрушать свои свойства и просто передавать их следующему дочернему компоненту с расширением…синтаксис, известный как оператор распространения.
Функциональный компонент React Arrow
С появлением JavaScript ES6 новые концепции кодирования были введены в JavaScript и, следовательно, в React. Например, функция JavaScript может быть выражена как лямбда (функция стрелки). Вот почему компонент функции иногда называют компонентом функции стрелки (или, возможно, также компонентом лямбда-функции). Давайте посмотрим на наш переработанный компонент React с функцией стрелки:
import React from 'react';
const App = () => {
const welcome = 'Привет, функциональный компонент!';
return <значение заголовка = {приветствие} />;
};
const Заголовок = ({значение}) => {
return
{значение}
;};
экспорт приложения по умолчанию;
Оба функциональных компонента React Arrow теперь используют тело функционального блока.Однако второй компонент можно сделать более легким с помощью краткого тела функции, поскольку он возвращает только выходные данные компонента, не выполняя никаких промежуточных действий. Если убрать фигурные скобки, явный возврат становится неявным возвратом, и его также можно опустить:
import React from 'react';
const App = () => {
const welcome = 'Привет, функциональный компонент!';
return <значение заголовка = {приветствие} />;
};
const Заголовок = ({значение}) =>
{значение}
;экспорт приложения по умолчанию;
При использовании стрелочных функций для компонентов React ничего не меняется для свойств.Они по-прежнему доступны как аргументы, как и раньше. Это компонент функции React с функциями ES6, выраженными стрелками, а не функциями ES5, которые являются более стандартным способом выражения функций в JS.
Примечание. Если вы столкнулись с ошибкой «Неожиданный токен функции стрелки компонента React», убедитесь, что для вашего приложения React доступен JavaScript ES6. Обычно при использовании приложения create-react-app это должно быть указано, в противном случае, если вы настроите проект самостоятельно, Babel включит ES6 и другие функции для вашего приложения React.
Функциональный компонент React без сохранения состояния
Каждый компонент, который мы видели до сих пор, можно назвать компонентом функции без сохранения состояния. Они просто получают входные данные в виде реквизита и возвращают результат в виде JSX:
(реквизиты) => JSX
. Входные данные, только если они доступны в виде свойств, формируют визуализированный выход. Эти компоненты не управляют состоянием и не имеют побочных эффектов (например, доступа к локальному хранилищу браузера). Люди называют их функциональными компонентами без состояния, потому что они не имеют состояния и выражаются функцией.Однако React Hooks позволил иметь состояние в компонентах функций.React Function Component: состояние
React Hooks позволили использовать состояние (и побочные эффекты) в функциональных компонентах. Наконец, мы можем создать компонент функции React с состоянием! Допустим, мы переместили всю логику в другой наш функциональный компонент и не передали ему никаких свойств:
import React from 'react';
const App = () => {
return <Заголовок />;
};
const Заголовок = () => {
const welcome = 'Компонент функции Hello!';
возврат
{приветствие}
;};
экспорт приложения по умолчанию;
Пока что у пользователя этого приложения нет возможности взаимодействовать с приложением и, следовательно, нет возможности изменить переменную приветствия.Приложение статичное и совсем не интерактивное. Состояние — это то, что делает компоненты React интерактивными; и захватывающе. В этом нам помогает перехватчик React:
import React, {useState} из response;
const App = () => {
return <Заголовок />;
};
const Заголовок = () => {
const [приветствие, setGreeting] = useState (
'Компонент функции Hello!'
);
возврат
{приветствие}
;};
экспорт приложения по умолчанию;
Ловушка useState принимает начальное состояние в качестве параметра и возвращает массив, который содержит текущее состояние в качестве первого элемента и функцию для изменения состояния в качестве второго элемента.Мы используем деструктуризацию массива JavaScript для доступа к обоим элементам с помощью сокращенного выражения. Кроме того, деструктурирование позволяет нам называть сами переменные.
Давайте добавим поле ввода для изменения состояния с помощью функции
setGreeting ()
:import React, {useState} from 'react';
const App = () => {
return <Заголовок />;
};
const Заголовок = () => {
const [приветствие, setGreeting] = useState (
'Компонент функции Hello!'
);
возврат (
{приветствие}
type = "text"
значение = {приветствие}
onChange = {event => setGreeting (событие .target.value)}
/>
);
};
экспорт приложения по умолчанию;
Предоставляя обработчик событий для поля ввода, мы можем что-то делать с функцией обратного вызова, когда поле ввода меняет свое значение. В качестве аргумента функции обратного вызова мы получаем синтетическое событие React, которое содержит текущее значение поля ввода. Это значение в конечном итоге используется для установки нового состояния для функционального компонента с помощью встроенной стрелочной функции.Позже мы увидим, как извлечь эту функцию оттуда.
Примечание. Поле ввода также принимает значение состояния компонента, потому что вы хотите контролировать состояние (значение) поля ввода и не позволять внутреннему состоянию собственного HTML-элемента брать верх. Таким образом, компонент стал управляемым.
Как вы видели, перехватчики React позволяют нам использовать состояние в компонентах функции React (стрелка). В то время как вы использовали бы метод setState для записи состояния в компонент класса, вы можете использовать ловушку useState для записи состояния в функциональный компонент.
Примечание. Если вы хотите использовать контекст React в функциональных компонентах, ознакомьтесь с перехватчиком контекста React под названием useContext для чтения из контекста React в компоненте.
Компонент функции React: обработчик событий
В предыдущем примере вы использовали обработчик событий onChange для поля ввода. Это правильно, потому что вы хотите получать уведомления каждый раз, когда изменяется внутреннее значение поля ввода. В случае других элементов HTML-формы в вашем распоряжении есть несколько других обработчиков событий React, таких как onClick, onMouseDown и onBlur.
Примечание. Обработчик события onChange — это только один из обработчиков элементов формы HTML. Например, кнопка предложит обработчик события onClick для реакции на события щелчка.
До сих пор мы использовали стрелочную функцию, чтобы встроить обработчик событий для выходного поля ввода. Что насчет извлечения его как отдельной функции внутри компонента? Тогда она станет именованной функцией:
import React, {useState} из response;
const App = () => {
return <Заголовок />;
};
const Заголовок = () => {
const [приветствие, setGreeting] = useState (
'Компонент функции Hello!'
);
const handleChange = event => setGreeting (event.целевое значение);
возврат (
{приветствие}
);
};
экспорт приложения по умолчанию;
Мы использовали стрелочную функцию для определения функции внутри компонента. Если вы раньше использовали методы класса в компонентах класса React, этот способ определения функций внутри компонента функции React является эквивалентом.Вы могли бы назвать это «Методами компонентов функции реакции», эквивалентными компонентам класса. Вы можете создать или добавить столько функций внутри функционального компонента, сколько хотите, чтобы они действовали как явные обработчики событий или инкапсулировали другую бизнес-логику.
Компонент функции React: функция обратного вызова
Все происходит в нашем компоненте дочерней функции. Ему не передаются никакие реквизиты, хотя вы уже видели, как строковая переменная для приветствия может быть передана из родительского компонента в дочерний компонент.Можно ли передать функцию компоненту как опору? Каким-то образом должна существовать возможность вызова функции компонента извне! Посмотрим, как это работает:
import React, {useState} из response;
const App = () => {
const [приветствие, setGreeting] = useState (
'Компонент функции Hello!'
);
const handleChange = event => setGreeting (event.target.value);
возврат (
<Заголовок заголовка = {приветствие} onChangeHeadline = {handleChange} />
);
};
const Headline = ({headline, onChangeHeadline}) => (
{headline}
);
экспорт приложения по умолчанию;
Вот и все.Вы можете передать функцию дочернему компоненту и обработать то, что происходит в родительском компоненте. Вы также можете выполнить что-то среднее в дочернем компоненте (компонент заголовка) для функции
onChangeHeadline
— например, обрезать значение — чтобы добавить дополнительную функциональность внутри дочернего компонента. Вот как вы могли бы вызвать функцию дочернего компонента из родительского компонента.Давайте рассмотрим этот пример на один шаг дальше, представив компонент Sibling для компонента Headline.Это может быть абстрактный компонент Input:
import React, {useState} из 'react';
const App = () => {
const [приветствие, setGreeting] = useState (
'Компонент функции Hello!'
);
const handleChange = event => setGreeting (event.target.value);
return (
Установить приветствие:
div>
);
};
const Заголовок = ({заголовок}) =>
{заголовок}
;const Input = ({value, onChangeInput, children}) => (
{children}
);
экспорт приложения по умолчанию;
Я считаю, что это идеальный, но минимальный пример, иллюстрирующий, как передавать функции между компонентами в качестве свойств; и, что более важно, как разделить функцию между компонентами.У вас есть один родительский компонент, который управляет логикой, и два дочерних компонента, которые являются братьями и сестрами, которые получают реквизиты. Эти свойства всегда могут включать функцию обратного вызова для вызова функции в другом компоненте. По сути, так можно вызывать функцию в разных компонентах в React.
Переопределить функцию компонента в React
Это не должно происходить часто, но я слышал, как люди задают мне этот вопрос. Как бы вы переопределили функцию компонента? Вам нужно использовать тот же подход, что и для переопределения любого другого переданного свойства компоненту, присвоив ему значение по умолчанию:
import React from 'react';
const App = () => {
const sayHello = () => console.журнал ('Привет');
return ;
};
const Button = ({handleClick}) => {
const sayDefault = () => console.log ('По умолчанию');
const onClick = handleClick || sayDefault;
возврат (
Button
);
};
экспорт приложения по умолчанию;
Вы также можете назначить значение по умолчанию в сигнатуре функции для деструктуризации:
import React from 'react';
const App = () => {
const sayHello = () => console.журнал ('Привет');
return ;
};
const Button = ({handleClick = () => console.log ('Default')}) => (
Button
);
экспорт приложения по умолчанию;
Вы также можете указать свойства по умолчанию для компонента функции React — это еще одна альтернатива:
import React from 'react';
const App = () => {
const sayHello = () => console.журнал ('Привет');
return ;
};
const Button = ({handleClick}) => (
Button
);
Button.defaultProps = {
handleClick: () => console.log ('По умолчанию'),
};
экспорт приложения по умолчанию;
Все эти подходы можно использовать для определения свойств по умолчанию (в данном случае функции по умолчанию), чтобы иметь возможность позже переопределить их извне, передав явное свойство (например,г. функция) к компоненту.
Асинхронная функция в компоненте с React
Другим частным случаем может быть асинхронная функция в компоненте React. Но в этом нет ничего особенного, потому что не имеет значения, выполняется функция асинхронно или нет:
import React from 'react';
const App = () => {
const sayHello = () =>
setTimeout (() => console.log ('Hello'), 1000);
return ;
};
const Button = ({handleClick}) => (
Button
);
экспорт приложения по умолчанию;
Функция выполняется с задержкой без каких-либо дальнейших инструкций с вашей стороны внутри компонента.Компонент также будет выполнять асинхронный рендеринг в случае изменения свойств или состояния. Возьмите следующий код в качестве примера, чтобы увидеть, как мы устанавливаем состояние с искусственной задержкой, используя
setTimeout
:import React, {useState} from 'react';
const App = () => {
const [count, setCount] = useState (0);
const handleIncrement = () =>
setTimeout (
() => setCount (currentCount => currentCount + 1),
1000
);
const handleDecrement = () =>
setTimeout (
() => setCount (currentCount => currentCount - 1),
1000
);
return (
{count}
);
};
const Button = ({handleClick, children}) => (
{children}
);
экспорт приложения по умолчанию;
Также обратите внимание, что мы используем функцию обратного вызова в функции состояния
setCount
для доступа к текущему состоянию.Поскольку функции установки изuseState
выполняются асинхронно по своей природе, вы хотите убедиться, что вы выполняете изменение состояния в текущем состоянии, а не в каком-либо устаревшем состоянии.Эксперимент: если вы не будете использовать функцию обратного вызова в State Hook, а будете действовать непосредственно на счетную переменную (например,
setCount (count + 1)
), вы не сможете увеличить значение с От 0 до 2 быстрым двойным щелчком, потому что оба раза функция будет выполняться при состоянии счетчика 0.Узнайте больше о том, как получать данные с помощью функциональных компонентов с помощью React Hooks.
Компонент функции React: жизненный цикл
Если вы ранее использовали компоненты класса React, вы можете использовать такие методы жизненного цикла, как componentDidMount, componentWillUnmount и shouldComponentUpdate. У вас их нет в функциональных компонентах, поэтому давайте посмотрим, как вы можете их реализовать.
Прежде всего, у вас нет конструктора в функциональном компоненте. Обычно конструктор использовался в компоненте класса React для выделения начального состояния.Как вы видели, он вам не нужен в функциональном компоненте, потому что вы выделяете начальное состояние с помощью ловушки useState и настраиваете функции в функциональном компоненте для дальнейшей бизнес-логики:
import React, {useState} from ' реагировать ';
const App = () => {
const [count, setCount] = useState (0);
const handleIncrement = () =>
setCount (currentCount => currentCount + 1);
const handleDecrement = () =>
setCount (currentCount => currentCount - 1);
возврат (
{count}
Шаг
Decrement
);
};
экспорт приложения по умолчанию;
Функциональный компонент React: Mount
Во-вторых, существует жизненный цикл монтирования для компонентов React, когда они отображаются в первый раз.Если вы хотите выполнить что-то, когда компонент функции React смонтировал , вы можете использовать ловушку useEffect:
import React, {useState, useEffect} from 'react';
const App = () => {
const [count, setCount] = useState (0);
const handleIncrement = () =>
setCount (currentCount => currentCount + 1);
const handleDecrement = () =>
setCount (currentCount => currentCount - 1);
useEffect (() => setCount (currentCount => currentCount + 1), []);
возврат (
{count}
Шаг
Decrement
);
};
экспорт приложения по умолчанию;
Если вы попробуете этот пример, вы увидите, что счетчик 0 и 1 отображаются вскоре друг за другом.Первый рендеринг компонента показывает счетчик 0 от начального состояния — тогда как после того, как компонент действительно монтировался, Effect Hook запустится для установки нового состояния счетчика 1.
Важно отметить пустой массив как второй. аргумент для Effect Hook, который гарантирует срабатывание эффекта только при загрузке компонента (монтирование) и выгрузке компонента (размонтирование).
Эксперимент: если вы оставите второй аргумент ловушки эффекта пустым, вы столкнетесь с бесконечным циклом увеличения счетчика на 1, потому что ловушка эффекта всегда запускается после изменения состояния.Поскольку обработчик эффекта запускает другое изменение состояния, он будет запускаться снова и снова для увеличения счетчика.
Функциональный компонент React: обновление
Каждый раз, когда входящие реквизиты или состояние компонента меняются, компонент запускает повторную визуализацию для отображения последнего статус-кво, которое часто получается из реквизитов и состояния. Визуализация выполняет все, что находится в теле функционального компонента.
Примечание. Если функциональный компонент не обновляется должным образом в вашем приложении, это всегда хорошая первая попытка отладки для консольного состояния журнала и свойств компонента.Если оба не меняются, новый рендеринг не выполняется, и, следовательно, вы не видите консольный журнал вывода.
импортировать React, {useState, useEffect} из «реагировать»;
const App = () => {
console.log ('Отображается ли?');
.
reactjs — Статическое свойство функционального компонента React
Переполнение стека
- Около
Продукты
- Для команд
Переполнение стека
Общественные вопросы и ответыПереполнение стека для команд
Где разработчики и технологи делятся частными знаниями с коллегамиВакансии
Программирование и связанные с ним технические возможности карьерного ростаТалант
Нанимайте технических специалистов и создавайте свой бренд работодателяРеклама
Обратитесь к разработчикам и технологам со всего мира- О компании
.
reactjs — Функциональный компонент React с использованием состояния
Переполнение стека
- Около
Продукты
- Для команд
Переполнение стека
Общественные вопросы и ответыПереполнение стека для команд
Где разработчики и технологи делятся частными знаниями с коллегамиВакансии
Программирование и связанные с ним технические возможности карьерного ростаТалант
Нанимайте технических специалистов и создавайте свой бренд работодателяРеклама
Обратитесь к разработчикам и технологам со всего мира- О компании
.