КатегорииReactУроки

React урок 1 Основы

React — это open-source библиотека созданная в Facebook. Предлагает новый подход к созданию пользовательских интерфейсов на JavaScript. Если вы знакомы с партерном MVC, то React это V. Другими словами он отвечает за визуализацию и это кажется немного странным, с одним только слоем представления  далеко не уедешь. Но не переживайте мы рассмотрим не только React, как таковой, но и другие прикладные архитектуры, которые применяются вместе с ним для построения полноценных веб приложений.

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

  • Что такое React и обзор его преимуществ;
  • Как использовать JSX – расширение синтаксиса JavaScript используется в React для описания компонентов;
  • Как создавать компоненты, что такое реквизиты (props) и состояние (state);

Прежде чем мы начнем

Для работы нам потребуется Node.js и NPM. NPM поставляется вместе с Node.js надо только скачать и установить его c официально сайта https://nodejs.org/en/ . На нем имеется две версии LTS и Current, в принципе нам подойдет любая из них.

Определение React

Чтобы четко понимать что такое React, хочу предложить такой вариант:

React это библиотека для создания компонентно-ориентированных пользовательских интерфейсов с помощью JavaScript и (необязательно) XML.

Он включает концепцию разделения пользовательского интерфейса на компоненты, самодостаточный части, которые просто поддерживать, расширять и применять повторно.

Компоненты могут быть описаны на JavaScript, но это можно сделать и на ХМL с НTML подобным синтаксисом называемым JSX.

React можно использовать для построения компонентов в браузере, так и на стороне сервера, то есть итоговый HTML будет формироваться не на клиенте, а на сервере, что позволяет строить, так называемые изоморфные приложения + позволяет избежать проблем с SEO присущих одно-страничным приложениям. Но и это еще не все, с помощью React можно создать нативные мобильные интерфейсы (React Native).

Преимущества React

Реактивный рендеринг

До появления Ajax на любое действие пользователя для отображения новых данных перезагружалась вся веб страница. Что было не слишком эффективным решением, когда требуется обновить только часть данных. С появлением Ajax можно было обновлять данные на странице частями. Появились так называемые одно-страничные приложения, когда загружалась только одна страница и все последующие запросы обрабатывались без полной перезагрузки страницы.

Поскольку интерфейсы становятся все более сложными, возрастает и сложность управления состоянием данных приложений. Многие библиотеки используют двухстороннею привязку данных к интерфейсу и манипулируют DOM деревом напрямую. Но такой подход проигрывает в плане скорости.

Реактивный рендеринг проще в использовании, чем традиционное связывание данных. Он позволяет писать нам в декларативном стиле, как компоненты должны выглядеть и вести себя. Что бы не изменять DOM дерево при каждом изменении данных, в React есть легковесная копия DOM дерева которая содержит текущие состояние. При изменении данных  в виртуальном React DOM дереве проходить сравнение с реальным DOM и изменения  происходят только там где это реально необходимо. Что делает React очень быстрым и эффективным.

Компонент-ориентированная разработка

В React все состоит из компонентов, которые являются самодостаточными строительными блоками. Вся эта красота преследует принцип «разделяй и властвуй» при котором ни какая часть не должна быть особенно сложной. Из более мелких компонентов можно легко создавать сложные и более многофункциональные компоненты.

Гибкая абстракция модели документа

React имеет свое собственное представление пользовательского интерфейса, которое абстрагирует базовую модель документа. Наиболее заметным преимуществом этого подхода заключается в том, что она позволяет использовать те же принципы для визуализации HTML, так и например нативных пользовательских интерфейсов IOS и Android. А еще это дает следующие преимущества:

  • События ведут себя в соответствии со стандартами образом во всех браузерах и устройствах;

  • Итоговый HTML React компонентов может быть построен на стороне сервера, что позволяет избежать проблем с SEO и строить изоморфные приложения;

Hello World на React

class Hello extends React.Component {
	render() {
		return (
			<h1>Hello World</h1>
		)
	}
}

По сути это простой JavaScript ES6 класс, с единственным методом render, который и отвечает за обрисовку компонента. Вы должно быть заметили в середине <h1>Hello World</h1> это и есть XML декларативная разметка для описания компонентов React, а все это в месте называется JSX. Который должен быть переведен в простой JS, а для этого нам понадобятся дополнительные инструменты позже мы их настроим.

Reаct – рабочий процесс

Рабочий процесс выглядит примерно так:

  • После написания JSX должен автоматически превращаться в JS

  • Писать код в виде модулей

  • Уметь управлять зависимостями

  • Создать JS файлы и map файлы для отладки

Основная структура проекта React содержит:

  • Папку с исходниками, содержащую все модули JS

  • Файл index.html.

  • package.json – представляет собой стандартный файл манифеста NPM

  • Модули для сборки проекта, которые помогут с трасформацией JSX в JS. Использование модулей позволяет организовать код, разделив его на несколько файлов, каждый из которых декларирует свои собственные зависимости. Таких модулей множество. Rect сообщество приняло Webpack, как предпочтительный инструмент для решения данных задач.

struct

Быстрый старт

Тут можно найти уже настроенный начальный проект https://github.com/pro-react/react-app-boilerplate

Не забудьте выполнить команды

npm i

Создание первого компонента

import React, {Component} from 'react';
import {render} from 'react-dom';
class App extends Component {
    render() {
        return (
            <h1>Hello World</h1>
        );
    }
}
render(<App />, document.getElementById('root'));

npm start — запуск приложения

result1

Динамические значения
В JSX значения записанные в фигурные скобки {} вычисляется как выражение JS и визуализируется в разметке. Пример:

import React, {Component} from 'react';
import {render} from 'react-dom';
class App extends Component {
    render() {
        var place = "World!!";
        return (
            <h1>Hello {place}</h1>
        );
    }
}
render(<App />, document.getElementById('root'));

Композиция компонентов

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

Реквизиты (props)

Одним из ключевых факторов, чтобы сделать компоненты многократно используемыми и компонуемыми является возможность передавать в них данные. React реализует это принцип через атрибуты дочерних компонентов. То есть передача возможно от родителя ребенку. Давайте в качестве примера создадим простой список продуктов.

import React, {Component} from 'react';
import {render} from 'react-dom';
// Parent Component
class GroceryList extends Component {
    render() {
        return (
            <ul>
                <ListItem quantity="1" name="Bread" />
                <ListItem quantity="6" name="Eggs" />
                <ListItem quantity="2" name="Milk" />
            </ul>
        );
    }
}
// Child Component
class ListItem extends Component {
    render() {
        return (
            <li>
                {this.props.quantity} × {this.props.name}
            </li>
        );
    }
}
render(<GroceryList />, document.getElementById('root'));

Помимо доступа к свойствам через атрибуты можно получить через props.children содержимое между тегами компонента.

import React, {Component} from 'react';
import {render} from 'react-dom';
// Parent Component
class GroceryList extends Component {
    render() {
        return (
            <ul>
                <ListItem quantity="1">Bread</ListItem>
                <ListItem quantity="6">Eggs</ListItem>
                <ListItem quantity="2">Milk</ListItem>
            </ul>
        );
    }
}
// Child Component
class ListItem extends Component {
    render() {
        return (
            <li>
                {this.props.quantity} × {this.props.children}
            </li>
        );
    }
}
render(<GroceryList />, document.getElementById('root'));

Приложение Канбан Доска

В этом уроках мы создадим инструмент управления проектами в Канбан стиле. Приложение представляет собой доску с разделением на области по текущему статусу задач. При изменении статуса задачи она перемещается в новую область с соответствующим статусом.

app

Наш окончательный проект будет выглядеть как на рисунке ниже

resultApp

Иерархия компонентов в нашем будущем приложении

Принципы разделения на компоненты:

  • Помните, что компоненты должны быть небольшими и иметь одну область ответственности. Другими словами компонент в идеале должен делать только одну вещь. Если компонент разрастается его надо разбить на более мелкие компоненты.
  • Проанализируйте макет проекта, это даст вам подсказки как можно разделить его на компоненты.
  • Обратите внимание на модель данных. Попробуйте разбить на компоненты так, что бы один компонент представлял собой ровно одну часть вашей модели данных.

Если использовать эти рекомендации то скорей всего вы придете к композиции компонентов показанных на рисунке ниже.

compositApp

Важность реквизитов (props)

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

Создание компонентов
Определившись с иерархией компонентов, пришло время для их создания. Есть два очевидных подхода к построению компонентов: сверху вниз или снизу вверх. Что бы получить представление о всех реквизитах (props)  используемых в дочерних компонентах, то имеет смысл начать строить свои компоненты сверху вниз.
Кроме того, чтобы было проще поддерживать наш проект, мы создадим для каждого компонента свой собственный файл JS.

App.js

На данном этапе файл App.js будет очень простым. Он будет содержать только данные, передаваемые дальше по иерархии компонентов. Сами данные будут храниться в локальной переменной, но в последующем мы это поправим и данные будет поступать через API сервера.

import React, {Component} from 'react';
import {render} from 'react-dom';
import KanbanBoard from './KanbanBoard';
let cardsList = [
    {
        id: 1,
        title: "Read the Book",
        description: "I should read the whole book",
        status: "in-progress",
        tasks: []
    },
    {
        id: 2,
        title: "Write some code",
        description: "Code along with the samples in the book",
        status: "todo",
        tasks: [
            {
                id: 1,
                name: "ContactList Example",
                done: true
            },
            {
                id: 2,
                name: "Kanban Example",
                done: false
            },
            {
                id: 3,
                name: "My own experiments",
                done: false
            }
        ]
    }
];
render(<KanbanBoard cards={cardsList} />, document.getElementById('root'));

KanbanBoard компонент (KanbanBoard.js)

Этот компонент должен уметь принимать данные для создания последующих компонентов, а точнее List (списков задач).

import React, {Component} from 'react';
import List from './List';
class KanbanBoard extends Component {
    render() {
        return (
            <div className="app">
                <List id='todo' title="To Do" cards={this.props.cards.filter((card) => card.status === "todo")}/>
                <List id='in-progress' title="In Progress" cards={this.props.cards.filter((card) => card.status === "in-progress")}/>
                <List id='done' title='Done' cards={this.props.cards.filter((card) => card.status === "done")}/>
            </div>
        );
    }
}
export default KanbanBoard;

List Component (List.js)

Компонент списка должен уметь отображать название списка (текущий статус задач) и передавать данные для создания компонентов Card.

import React, { Component } from 'react';
import Card from './Card';
class List extends Component {
    render() {
        var cards = this.props.cards.map((card) => {
            return <Card id={card.id}
                         title={card.title}
                         description={card.description}
                         tasks={card.tasks} />
        });
        return (
            <div className="list">
                <h1>{this.props.title}</h1>
                {cards}
            </div>
        );
    }
}
export default List;

Card Component (Card.js)

Каждая карта должна иметь название, описание и список задач.

card

import React, { Component } from 'react';
import CheckList from './CheckList';
class Card extends Component {
    render() {
        return (
            <div className="card">
                <div className="card__title">{this.props.title}</div>
                <div className="card__details">
                    {this.props.description}
                    <CheckList cardId={this.props.id} tasks={this.props.tasks} />
                </div>
            </div>
        );
    }
}
export default Card;

Обратите внимание на использование атрибута className в описании компонента по сути это эквивалент атрибута class в HTML. Но поскольку JSX в итоге превращается в JS в качестве атрибута не рекомендуется использовать слово class как в обычном HTML, так как это слово является зарезервированным в JS.

Checklist Component (CheckList.js)

И наконец это последний в нашей иерархии компонент, отвечающий за список задач.

import React, {Component} from 'react';
class CheckList extends Component {
    render() {
        let tasks = this.props.tasks.map((task) => (
            <li className="checklist__task">
                <input type="checkbox" defaultChecked={task.done}/>
                {task.name}
                <a href="#" className="checklist__task--remove"/>
            </li>
        ));
        return (
            <div className="checklist">
                <ul>{tasks}</ul>
            </div>
        );
    }
}
export default CheckList;

Последние штрихи

Теперь когда мы закончили с компонентами, давайте наведем красоту, для этого создадим файл style.css

* {
    box-sizing: border-box;
}
html, body, #app {
    height: 100%;
    margin: 0;
    padding: 0;
}
body {
    background: #eee;
    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
h1 {
    font-weight: 200;
    color: #3b414c;
    font-size: 20px;
}
ul {
    list-style-type: none;
    padding: 0;
    margin: 0;
}
.app {
    white-space: nowrap;
    height: 100%;
}
.list {
    position: relative;
    display: inline-block;
    vertical-align: top;
    white-space: normal;
    height: 100%;
    width: 33%;
    padding: 0 20px;
    overflow: auto;
}
.list:not(:last-child):after {
    content: "";
    position: absolute;
    top: 0;
    right: 0;
    width: 1px;
    height: 99%;
    background: linear-gradient(to bottom, #eee 0%, #ccc 50%, #eee 100%) fixed;
}
.card {
    position: relative;
    z-index: 1;
    background: #fff;
    width: 100%;
    padding: 10px 10px 10px 15px;
    margin: 0 0 10px 0;
    overflow: auto;
    border: 1px solid #e5e5df;
    border-radius: 3px;
    box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
}
.card__title {
    font-weight: bold;
    border-bottom: solid 5px transparent;
}
.card__title:before {
    display: inline-block;
    width: 1em;
    content: '';
}
.card__title--is-open:before {
    content: '';
}
.checklist__task:first-child {
    margin-top: 10px;
    padding-top: 10px;
    border-top: dashed 1px #ddd;
}
.checklist__task--remove:after{
    display: inline-block;
    color: #d66;
    content: "+";
}

Не забудьте подключить новый файл style.css в index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Kanban App</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <div id="root"></div>
        <script type="text/javascript" src="bundle.js"></script>
    </body>
</html>

Что такое состояние (state)
До сих пор мы видели только статические компоненты. Что бы добавить динамики мы должны как-то сообщать React, что мы хотим поменять и когда. В React компонентах изменяемые данных объявляются и хранятся в внутри this.state. Обратите внимание что this.state у каждого компонента своей и this.state изменяется через вызов this.setState(). Принцип следующий, когда мы вызываем this.setState() проходит реактивный рендеринг компонента и его детей. Как уже упоминало это довольно быстрая операция за счет использования виртуального DOM дерева.

Kanban App: Прячем подробности Cart

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

class Card extends Component {
    constructor() {
        super(...arguments);
        this.state = {
            showDetails: false
        };
    }
    render() {
        ...
    }
}
export default Card;

Здесь мы задали значение по умолчанию

class Card extends Component {
    constructor() {
        ...
    }
    render() {
        let cardDetails;
        if (this.state.showDetails) {
            cardDetails = (
                <div className="card__details">
                    {this.props.description}
                    <CheckList cardId={this.props.id} tasks={this.props.tasks} />
                </div>
            );
        }
        return (
            <div className="card">
                <div className="card__title">{this.props.title}</div>
                {cardDetails}
            </div>
        );
    }
}
export default Card;

Тут появилось условие если текущее значение this.state.showDetails отрицательно то не показывать детали задачи или наоборот.

Теперь давайте добавим событие о нажатии при котором будем менять состояние.

...
render() {
    ...
    return (
        <div className="card" onClick={()=>this.setState({showDetails: !this.state.showDetails})}>{this.props.title}>
            <div className="card__title">{this.props.title}</div>
            {cardDetails}
        </div>
    );
}
...

Подведем итоги

Мы узнали что такое React, какие преимущества нам дает, в первую очередь это производительность, декларативность и компонент-ориентированный подход к построению пользовательских интерфейсов. Так же мы создали несколько компонентов, узнали основные концепции: метод визуализации (render), JSX, реквизиты (props) и состояние (stats).

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *