В сегодняшней части перевода учебного курса по React мы поговорим о свойствах компонентов. Это — одна из важнейших концепций, нашедших отражение в данной библиотеке.
> Часть 1: обзор курса, причины популярности React, ReactDOM и JSX
> Часть 2: функциональные компоненты
> Часть 3: файлы компонентов, структура проектов
> Часть 4: родительские и дочерние компоненты
> Часть 5: начало работы над TODO-приложением, основы стилизации
> Часть 6: о некоторых особенностях курса, JSX и JavaScript
> Часть 7: встроенные стили
> Часть 8: продолжение работы над TODO-приложением, знакомство со свойствами компонентов
> Часть 9: свойства компонентов
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 > h3 {
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"/>
<h3><font color="#3AC1EF">?Mr. Whiskerson</font></h3>
<p>Phone: (212) 555-1234</p>
<p>Email: mr.whiskaz@catnap.meow</p>
</div>
<div className="contact-card">
<img align="center" src="http://placekitten.com/400/200"/>
<h3><font color="#3AC1EF">?Fluffykins</font></h3>
<p>Phone: (212) 555-2345</p>
<p>Email: fluff@me.com</p>
</div>
<div className="contact-card">
<img align="center" src="http://placekitten.com/400/300"/>
<h3><font color="#3AC1EF">?Destroyer</font></h3>
<p>Phone: (212) 555-3456</p>
<p>Email: ofworlds@yahoo.com</p>
</div>
<div className="contact-card">
<img align="center" src="http://placekitten.com/200/100"/>
<h3><font color="#3AC1EF">?Felix</font></h3>
<p>Phone: (212) 555-4567</p>
<p>Email: thecat@hotmail.com</p>
</div>
</div>
)
}
export default App
App
. Учитывая же то, о чём мы говорили на предыдущих занятиях, можно пойти и дальше — подумать об универсальном компоненте, который можно настраивать, передавая ему атрибуты или свойства.App
. Например — такой:<div className="contact-card">
<img align="center" src="http://placekitten.com/300/200"/>
<h3><font color="#3AC1EF">?Mr. Whiskerson</font></h3>
<p>Phone: (212) 555-1234</p>
<p>Email: mr.whiskaz@catnap.meow</p>
</div>
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"/>
<h3><font color="#3AC1EF">?Mr. Whiskerson</font></h3>
<p>Phone: (212) 555-1234</p>
<p>Email: mr.whiskaz@catnap.meow</p>
</div>
)
}
export default ContactCard
ContactCard
, в том виде, в котором он сейчас существует, может стать такая вот простая функция, которая, ничего не принимая, просто возвращает сумму двух чисел:function addNumbers() {
return 1 + 1
}
function addNumbers(a, b) {
return a + b
}
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"/>
<h3><font color="#3AC1EF">?Mr. Whiskerson</font></h3>
<p>Phone: (212) 555-1234</p>
<p>Email: mr.whiskaz@catnap.meow</p>
</div>
<div className="contact-card">
<img align="center" src="http://placekitten.com/400/200"/>
<h3><font color="#3AC1EF">?Fluffykins</font></h3>
<p>Phone: (212) 555-2345</p>
<p>Email: fluff@me.com</p>
</div>
<div className="contact-card">
<img align="center" src="http://placekitten.com/400/300"/>
<h3><font color="#3AC1EF">?Destroyer</font></h3>
<p>Phone: (212) 555-3456</p>
<p>Email: ofworlds@yahoo.com</p>
</div>
<div className="contact-card">
<img align="center" src="http://placekitten.com/200/100"/>
<h3><font color="#3AC1EF">?Felix</font></h3>
<p>Phone: (212) 555-4567</p>
<p>Email: thecat@hotmail.com</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="mr.whiskaz@catnap.meow"
/>
<ContactCard
name="Fluffykins"
imgUrl="http://placekitten.com/400/200"
phone="(212) 555-2345"
email="fluff@me.com"
/>
<ContactCard
name="Destroyer"
imgUrl="http://placekitten.com/400/300"
phone="(212) 555-3456"
email="ofworlds@yahoo.com"
/>
<ContactCard
name="Felix"
imgUrl="http://placekitten.com/200/100"
phone="(212) 555-4567"
email="thecat@hotmail.com"
/>
</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"/>
<h3><font color="#3AC1EF">?Mr. Whiskerson</font></h3>
<p>Phone: (212) 555-1234</p>
<p>Email: mr.whiskaz@catnap.meow</p>
</div>
)
}
export default ContactCard
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"/>
<h3><font color="#3AC1EF">?Mr. Whiskerson</font></h3>
<p>Phone: (212) 555-1234</p>
<p>Email: mr.whiskaz@catnap.meow</p>
</div>
)
}
export default ContactCard
props
, получаемый компонентом, в консоль.ContactCard.js
. Их именно столько из-за того, что мы создаём четыре экземпляра компонента ContactCard
.props
.props.imgUrl
так:<img align="center" src=props.imgUrl/>
<img align="center" src={props.imgUrl}/>
import React from "react"
function ContactCard(props) {
return (
<div className="contact-card">
<img align="center" src={props.imgUrl}/>
<h3><font color="#3AC1EF">?{props.name}</font></h3>
<p>Phone: {props.phone}</p>
<p>Email: {props.email}</p>
</div>
)
}
export default ContactCard
Phone:
и Email:
с пробелами, следующими за ними, так как эти тексты используются во всех компонентах. Если теперь взглянуть на страницу приложения, то можно заметить, что она содержит четыре разных карточки.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: "mr.whiskaz@catnap.meow"
}}
/>
<ContactCard
name="Fluffykins"
imgUrl="http://placekitten.com/400/200"
phone="(212) 555-2345"
email="fluff@me.com"
/>
<ContactCard
name="Destroyer"
imgUrl="http://placekitten.com/400/300"
phone="(212) 555-3456"
email="ofworlds@yahoo.com"
/>
<ContactCard
name="Felix"
imgUrl="http://placekitten.com/200/100"
phone="(212) 555-4567"
email="thecat@hotmail.com"
/>
</div>
)
}
export default App
App
, используемого для создания первого экземпляра компонента ContactCard
, правильная работа приложения была нарушена. Вот как теперь будет выглядеть его страница.console.log(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}/>
<h3><font color="#3AC1EF">?{props.contact.name}</font></h3>
<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: "mr.whiskaz@catnap.meow"
}}
/>
<ContactCard
contact={{
name: "Fluffykins",
imgUrl: "http://placekitten.com/400/200",
phone: "(212) 555-2345",
email: "fluff@me.com"
}}
/>
<ContactCard
contact={{
name: "Destroyer",
imgUrl: "http://placekitten.com/400/300",
phone: "(212) 555-3456",
email: "ofworlds@yahoo.com"
}}
/>
<ContactCard
contact={{
name: "Felix",
imgUrl: "http://placekitten.com/200/100",
phone: "(212) 555-4567",
email: "thecat@hotmail.com"
}}
/>
</div>
)
}
export default App
К сожалению, не доступен сервер mySQL