Учебный курс по React, часть 10: практикум по работе со свойствами компонентов и стилизации +22


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

image

> Часть 1: обзор курса, причины популярности React, ReactDOM и JSX
> Часть 2: функциональные компоненты
> Часть 3: файлы компонентов, структура проектов
> Часть 4: родительские и дочерние компоненты
> Часть 5: начало работы над TODO-приложением, основы стилизации
> Часть 6: о некоторых особенностях курса, JSX и JavaScript
> Часть 7: встроенные стили
> Часть 8: продолжение работы над TODO-приложением, знакомство со свойствами компонентов
> Часть 9: свойства компонентов
> Часть 10: практикум по работе со свойствами компонентов и стилизации
> Часть 11: динамическое формирование разметки и метод массивов map

Занятие 20. Практикум. Свойства компонентов, стилизация


> Оригинал

?Задание


  1. Создайте новый проект React-приложения.
  2. Выведите на странице приложения компонент App, код которого должен находиться в отдельном файле.
  3. Компонент App должен выводить 5 компонентов Joke, содержащих анекдоты. Выведите эти компоненты так, как вам хочется.
  4. Каждый компонент Joke должен принимать и обрабатывать свойство question, для основной части анекдота, и свойство punchLine — для его ключевой фразы.

?Дополнительное задание


Некоторые анекдоты целиком состоят из ключевой фразы. Например: «It’s hard to explain puns to kleptomaniacs because they always take things literally». Подумайте над тем, как компонент Joke может вывести лишь переданное ему свойство punchLine, в том случае, если свойство question не задано. Поэкспериментируйте со стилизацией компонентов.

?Решение


Основное задание


Файл index.js будет выглядеть вполне привычно:

import React from "react"
import ReactDOM from "react-dom"

import App from "./App"

ReactDOM.render(<App />, 
    document.getElementById("root"))

Вот код файла App.js:

import React from "react"
import Joke from "./Joke"

function App() {
    return (
        <div>
            <Joke 
                question="What's the best thing about Switzerland?" 
                punchLine="I don't know, but the flag is a big plus!"
            />
            
            <Joke 
                question="Did you hear about the mathematician who's afraid of negative numbers?" 
                punchLine="He'll stop at nothing to avoid them!"
            />
            
            <Joke 
                question="Hear about the new restaurant called Karma?" 
                punchLine="There’s no menu: You get what you deserve."
            />
            
            <Joke 
                question="Did you hear about the actor who fell through the floorboards?" 
                punchLine="He was just going through a stage."
            />
            
            <Joke 
                question="Did you hear about the claustrophobic astronaut?" 
                punchLine="He just needed a little space."
            />
            
        </div>
    )
}

export default App

Обратите внимание на то, что, так как файл компонента Joke расположен в той же папке, что и файл компонента App, мы импортируем его командой import Joke from "./Joke". Из App мы возвращаем несколько элементов, поэтому весь вывод нужно обернуть в некий тег, например — в тег <div>. Экземплярам компонента мы передаём свойства question и punchLine.

Вот код файла Joke.js:

import React from "react"

function Joke(props) {
    return (
        <div>
            <h3>Question: {props.question}</h3>
            <h3>Answer: {props.punchLine}</h3>
            <hr/>
        </div>
    )
}

export default Joke

Здесь, при объявлении функции Joke, мы указываем параметр props. Напомним, что именно такое имя используется по сложившейся традиции. На самом деле оно может быть любым, но лучше называть его именно props.

Из компонента мы возвращаем несколько элементов — поэтому они заключены в тег <div>. С помощью конструкций props.question и props.punchLine мы обращаемся к свойствам, переданным экземпляру компонента при его создании. Эти свойства становятся свойствами объекта props. Они заключены в фигурные скобки из-за того, что JavaScript-код, используемый в JSX-разметке, нужно оформлять фигурными скобками. Иначе система примет имена переменных за обычный текст. После пары элементов <h3>, в одном из которых выводится основной текст анекдота, а в другой — его ключевая фраза, находится элемент <hr/>, описывающий горизонтальную линию. Такие линии будут выводиться после каждого анекдота, разделяя их.

Вот как выглядит проект приложения в VSCode.


Приложение в VSCode

Вот страница приложения.


Страница приложения в браузере

Дополнительное задание


Напомним, что основная цель дополнительного задания заключается в том, чтобы организовать правильный вывод анекдотов, которые целиком состоят из ключевой фразы. Это выражается в том, что, при создании экземпляра компонента Joke, ему передают лишь свойство punchLine, а свойство question не передают. Создание экземпляра подобного компонента выглядит так:

<Joke 
    punchLine="It’s hard to explain puns to kleptomaniacs because they always take things literally."
/>

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


Неправильно сформированная страница приложения

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

Забегая вперёд отметим, что в будущих частях курса мы поговорим об условном рендеринге. С помощью этого подхода к рендерингу можно эффективно решать задачи, подобные нашей. Пока же мы попытаемся воспользоваться средствами стилизации страниц. А именно, сделаем так, чтобы, если компоненту не передаётся свойство question, соответствующий фрагмент возвращаемой им JSX-разметки не отображался бы на странице. Вот полный код компонента Joke, в котором реализован один из возможных подходов решения нашей проблемы средствами CSS:

import React from "react"

function Joke(props) {
    return (
        <div>
            <h3 style={{display: props.question ? "block" : "none"}}>Question: {props.question}</h3>
            <h3>Answer: {props.punchLine}</h3>
            <hr/>
        </div>
    )
}

export default Joke

Первому элементу <h3> мы назначаем стиль, который определяется в процессе создания экземпляра компонента на основе наличия в объекте свойства props.question. Если это свойство в объекте есть, элемент принимает стиль display: block и выводится на страницу, если нет — display: none и на страницу не выводится. К тому же эффекту приведёт и использование такой конструкции:

<h3 style={{display: !props.question && "none"}}>Question: {props.question}</h3>

Здесь стиль display: none назначается элементу в том случае, если у объекта props нет свойства question, в противном случае свойству display не назначается ничего.

Теперь страница приложения в браузере будет выглядеть так, как показано ниже.


Правильная обработка компонентом ситуации, в которой ему не передают свойство question

Можно заметить, что все элементы, формируемые компонентом Joke, выглядят одинаково. Подумаем над тем, как выделить те из них, которым передаётся лишь свойство punchLine. Решим эту задачу, используя встроенные стили, и тот подход, который мы рассмотрели выше. Вот обновлённый код компонента Joke:

import React from "react"

function Joke(props) {
    return (
        <div>
            <h3 style={{display: !props.question && "none"}}>Question: {props.question}</h3>
            <h3 style={{color: !props.question && "#888888"}}>Answer: {props.punchLine}</h3>
            <hr/>
        </div>
    )
}

export default Joke

А вот как выглядит то, что теперь выводится на страницу приложения.


Стилизация элемента, который отличается от других

Теперь, после того, как мы поработали над компонентом Joke, он стал более универсальным и лучше подходящим для повторного использования.

Итоги


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

Уважаемые читатели! Если ваше решение задач этого практикума отличается от предложенного — просим о нём рассказать.




К сожалению, не доступен сервер mySQL