Первые серьезные строки на React.js [Pt.3 – Finally starting for real]

В прошлых монотонных рассказах мы занимались долгой и утомительной настройкой вебпака и вообще “среды” для создания React приложений.

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

Впрочем, начнем с азов, затронутых еще в первом рассказе. Заглянем в файл index.js, он скорее всего находится в папке src, если ты продолжаешь с пути c-r-a, либо прямо в корне проекта, если решил в лоб принять удар тяжелой и героической самостоятельной настройки вебпака.

Мы завершили наше прошлое знакомство с кодом реакта на небольшом примере двух вариантов компонентов, умном и глупом, как я, пожалуй, буду дальше их называть. Первый по моей скромной (и скорее всего не очень надежной) терминологии имеет свою не визуальную логику, второй просто отображает разметку подставляя переданные параметры.
Как я уже говорил, существует еще как минимум пара типов и принципов разделения компонентов, но это разделение несет с собой несколько тонких граней, которые с наскока легко проморгать.

Для простоты подхода (и соблюдения традиций) мы начнем с глупых – stateless – компонентов.
На данный момент существует 3 способа их создания, впрочем последний (и исторически первый) через React.createClass мы не будем разбирать как технически устаревающий (и не зря же мы проходили через все страдания вебпака и бейбла)

class X extends React.Component

import React, { Component } from 'react'; 
import ReactDOM from 'react-dom'; 

class ColoredDiv extends React.Component {
    render() {
        const {color, fontSize: fz} = this.props;
        return <div style={{background: this.props.bgColor, color, fontSize: fz}}>Me colored, yay!</div>
    }
}

ReactDOM.render(<ColoredDiv bgColor="green" color="red" fontSize="14px"/>, document.getElementById('root'));

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

Разберем же наш простенький код по полочкам:
import X from 'x'; – механизм загрузки и сборки модулей, для которого мы и используем вебпак, так как это до сих пор достаточно далекий от браузерного стандарта функционал. Как можно правильно догадаться, import React from 'react' дает доступ к функционалу реакта посредством константы React (также любой импорт говорит вебпаку загрузить указанную библиотеку, что бывает важно в некоторых случаях).
class X extends React.Component – синтаксис для создания “класса” в ES6, при этом мы наследуем от базового класса реакта (потому что надо).
render() это метод нашего класса, который будет использовать реакт для создания разметки компонента – ее рендера.

this.props это специальный неизменяемый объект (свойство\параметр), в который реакт помещает переданные компоненту свойства (prop(ertie)s).

Непосредственно процесс передачи можно увидеть глянув на последнюю строчку – ReactDOM.render. Первым аргументом для него идет JSX разметка (технически возврат React.createElement, но это ненужные детали). Мы использовали имя созданного компонента (класса) и вставили несколько атрибутов: bgColor, color, fontSize эти атрибуты и попадают в объект props компонента.

Как можно заметить, в рендере самого компонента мы возвращаем JSX разметку подобную той, что передавали в ReactDOM.render (наблюдаешь связь?). И как можно заметить, фигурные скобки в атрибутах служат для передачи JS значений, включая объекты как в style (отчего там получились по две фигурные скобки, внешние для обозначения компилятору что идет JS код, внутренние уже для самого объекта), так и просто строки или числа.

Также я использовал сразу три способа использования переменных из свойств (props): доступ напрямую this.props.bgColor, и деструктуризации {color} = this.props и {fontSize: fz} = this.props, третья отличается от второй лишь тем, что мы переименовали переменную перед использованием. Как правило используется второй и третий тип, так как это позволяет сразу в начале рендера указать, какие свойства используются в компоненте.

Как можно догадаться, фигурные скобки позволяют использовать JS не только в атрибутах:

render() {
    const {color, fontSize: fz } = this.props;
    return (<div style={{background: this.props.bgColor, color, fontSize: fz}}>
        {Math.random() >= 0.5 ? 'Me colored, yay!' : 'Me no random!'}
    </div>)
}

Помимо скромных забав со случайными числами таким образом можно использовать любой JS код, который возвращает значения (строки, числа, элементы реакта (JSX) или массивы перечисленных типов), к повсеместно используемому примеру, Array.map:

class ColoredDiv extends React.Component{
    render() {
        const {color, fontSize: fz, rows } = this.props;
        return (<div style={{background: this.props.bgColor, color, fontSize: fz}}>
            {rows.map(row => <li>{row}</li>)}
        </div>);
    }
}

ReactDOM.render(<ColoredDiv 
    color="#ab00ff" 
    bgColor="white" 
    fontSize="14px" 
    rows={[
        'Me colored, yay!', 
        'Me colored, nope second try!', 
        'No random is it!'
    ]}
/>, document.getElementById('root'));

Как можно ожидать (или нет, с непривычки) – ColoredDiv выведет уже знакомый стилизованный div и li со строками из массива переданного через свойство rows (ReactDOM.render).
Если ты еще не ознакомился с функциональными методами массивов, постарайся разобраться хотя бы с минимальным набором map, filter, reduce, и опционально forEach, последний технически идентичен map, просто не возвращает значений. Но особенно непредсказуемо полезным может оказаться reduce. А первые два ты скорее всего будешь использовать повсеместно, работая с реактом (и очень вероятно без него тоже).

Помимо бездумного разглядывания кода, я предлагаю тебе самостоятельно побаловаться с нашим скромным примером, использовав все три перечисленных типа данных доступных для вывода, и в целом привыкнуть к подобию JSX на HTML и его отличительным особенностям, которые позволяют творить (иногда к сожалению) что угодно за счет вставки чистого JS кода в разметку. Особенно интересно становится, когда ты заканчиваешь играть со стандартными HTML елементами и начинаешь компоновать разметку компонентами реакта.

Итак, что мы успели сделать:
1. Создали класс-компонент ColoredDiv через class ColoredDiv extends React.Component { ... },
2. Добавили в него метод render() { ... } который возвращает JSX разметку (<div style={{ ... }}>...</div>),
3. Отрендерили (или правильнее сказать монтировали (mount)) созданный компонент посредством ReactDOM.render(<ColoredDiv ... />, realDOMElem),
4. Передали свойства (props) компоненту ColoredDiv через ReactDOM.render и использовали их.

Базовое знакомство с работой реакта? Завершено.

Хоть это и скучно, но на сейчас почти хватит, осталось только глянуть второй способ записи глупых компонентов, о котором я говорил ранее:

const X = (props) => …

Как можно заметить, имея опыт с ES6, это просто “стрелочная” (arrow) функция. Такой тип записи компонентов называется функциональным (duh!) и является более простой и удобной заменой относительно громоздкому классу. К слову, использовать стандартные функции теоретически тоже можно, но лично я такое не практикую.

Также я упоминал, что наш чрезмерно неумный компонент можно без дополнительных манипуляций преобразовать в функциональный:

const ColoredDiv = ({color, fontSize: fz, rows, ...props }) => 
<div style={{background: props.bgColor, color, fontSize: fz}}>
    {rows.map(row => <li>{row}</li>)}
</div>

Как всегда немного магии деструктуризации и условно громоздкая конструкция класса “сокращается” в два раза. Условно и кавычки подсказывают, что все не так просто. Куда большую пользу функциональные компоненты несут своей семантикой – они по определению не имеют своего состояния и поэтому они должны быть просты..
но.. никто не помешает сделать “умный” компонент-обертку который передает все данные и обработчики “глупому” функциональному компоненту.. который тем не менее содержит сотню строк разметки перемешанной с данными и обработчиками. И технически будет прав, но работать с этим все равно будет не очень приятно.
Что я хочу сказать – нельзя прятаться за терминами и определениями, оправдывая не очень хороший код (duh!x2), нужно стараться писать хороший код, помогая себе определенными терминами и абстракциями или шаблонами скрывающимися за ними.

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

nil commento load