05Sep

logo_og

Окунемся немного в прошлое и разберемся как вообще появился React, и зачем вообще нам нужны фреймворки. Вернемся лет на 10 назад к примеру, когда был только чистый JavaScript, зачастую он выполнял простейшие задачи, такие как валидация формы и.т.п. Ключевая концепция – это абстрагироваться от неких обыденных проблем, и решать более сложные, задачи. Так появились библиотеки и далее фреймворки. Т.е. абстрагируясь от того как должно меняться DOM дерево, был придуман Data Binding (two-way) и появились Angular, Backbone, Knockout, Ember. Т.е. идея была в том, чтобы максимально освободить разработчика от выполняя типовых задач и дать ему сконцентрироваться на поведении самого приложения. Data Binding (two-way Data Binding) в большинстве своем был реализован с помощью моделей –  MVС, MVVM. Этот паттерн пришел к нам из серверной разработки где используется уже много лет для построения API, сайтов. Мы разделяем наше приложение на модули, которые взаимодействуют между собой, выполняя свои узкоспециализированные задачи.

Model – модель

View – вид

Controller – контроллер

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

1

Есть дерево, некий View,

2

Есть данные пользователя живущие в модели: Name и Age. Контроллер знает, что от имени/возраста зависят указанные на картинке DOM NODEs и каждый раз когда что-то меняется мы следим за изменениями наших моделей, за изменениями данных. Нам необходимо знать, что именно поменялось. Как только в этой модели поменялось, например, Name или какое-то свойство, зависящее от Name, нам нужно пойти и поменять соответствующие DOM Nodes. Собственно, все вышеуказанные фреймворки это и делают. Ключевая идея MVС, MVVM Фреймворков в том, что они следят за изменениями данных, они знают какие элементы в реальном DOM от них зависят, и далее они идут и меняют их.

3

Такой подход хорош, но конечно же существует ряд оговорок. Такая архитектура лучше, чем ничего, но она привнесена из серверной разработки где есть свои «узкие места».  На сервере зачастую нам больше приходиться работать с самими данными и меньше с их отображениями. Узкие места на сервере это обычно база-данных, коммуникации между сервисами. Тогда как на клиенте узкое мест это работа с DOM деревом, и зачастую на клиенте больше интерактивности чем в классических MVC Фреймворках на сервере.

Поэтому с течением времени, с появлением сложных задач на Front-end появилась необходимость иметь архитектурные паттерны, которые больше подходят под клиентскую часть. Одним из первых кто решил отойти от концепции MVC стал React, привнеся свою концепцию виртуального DOM.
4

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

Дальше React делает div старого виртуального DOM и Div нового виртуального DOM и видит, что для того чтобы привести реальный DOM в актуальное состояние нужно изменить 2-3 элемента на страничке.

– Каждый раз, когда происходит изменения мы перестраиваем виртуальный DOM

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

В этом и есть главная концепция. Главное отличие от MVC Фреймворков в том, что не важно какие данные поменялись, нас интересует сам факт изменения, чтобы далее перестроить виртуальный DOM.

Почему реальный DOM не так быстр? Он значительно более объемный чем виртуальный. Виртуальный хранит исключительно структуру. Что важно, так это то, что нас перестает волновать DOM как таковой, мы можем, оперируя компонентами строить любые структуры. DOM скорее отсылка к истории. Т.е. мы можем использовать такую структуру при создании native мобильного приложения где такого понятия как DOM нет. Там есть React view, а далее React делает из них Android, IOS Views или же рендерит все в строку если мы работаем на сервере.

Поговорим о Babel.

Babel это Transpiler, стандартный для работы с JSX React. Т.е. он позволят писать на es6 и транслировать его в es5 стандарт. Сама команда facebook отказалась от собственного решения и предложила пользоваться Babel.

Пример из песочницы с

https://babeljs.io

Код страницы:

<div>  
<h1>Hello world , </h1>  
</div>  

транслируется из JSX

	"use strict";  
	  
	React.createElement(  
	  "div",  
	  null,  
	  React.createElement(  
	    "h1",  
	    null,  
	    "Hello world , "  
	  )  
	);  

Отметим что в React нет templates, как в других Фреймворках. Раньше это реализовывалось добавлением в HTML какого-то сложного поведения. React подошел к проблеме с другой стороны. Понимая ограниченность HTML, разработчики решили дать JS возможность по созданию страниц – JSX. По сути JSX это и есть JavaScript. Это позволяет к примеру, отлавливать ошибки на этапе компиляции, а не когда клиент зайдет на страницу. Здесь нет такого понятия как шаблоны.

Никто не пишет проекты используя JSX, поэтому с самого начала нужно будет использовать Babel для transpiling.

Откройте учебный проект, вы можете скачать его здесь.

Взглянем на babelrc – это файл в котором необходимо описать некоторые преобразования, которые вы хотите, чтобы Babel выполнил над вашими файлами.

{
    "presets": ["react", "es2015", "stage-0", "react-hmre"]
}

Первый из пресетов React превращает JSX в JS, далее подключаем es2015, stage-0 – подключение неких фич не вошедших в es6 (статические атрибуты классов, например).

Т.е. каждый файл будет преобразовываться в JS, ES6 в ES5, а на выходе мы получим, большой bundle.js который будет полностью на ES5.

https://webpack.github.io/

Посмотрите webpack.config

        var path = require('path')  
	var webpack = require('webpack')  
	  
	module.exports = {  
	    devtool: 'source-map',  
	    entry: [  
	        './src/app.js'  
	    ],  
	    output: {  
	        path: path.join(__dirname, 'build'),  
	        filename: 'bundle.js',  
	        publicPath: '/static/'  
	    },  
	    devServer: {  
	        historyApiFallback: true,  
	        proxy: [{  
	            path: '/api/*',  
	            target: 'http://localhost:3001'  
	        }]  
	    },  
	    module: {  
	        loaders: [  
	            {  
	                test: /\.jsx?/,  
	                loaders: ['babel'],  
	                include: path.join(__dirname, 'src')  
	            },  
	            {  
	                test: /\.css$/,  
	                loader: 'style-loader!css-loader'  
	            }  
	        ]  
	    }  
	}  

Web pack –  это программа позволяющая собрать большое количество модулей в один. Мы описываем здесь что есть исходный файл app.js из которого мы будем начинать нашу разработку который может импортировать разные модули и собирать их в один файл, для отправки на клиент. Перед тем как собирать файлы в один модуль он сначала пропустит их код через Babel. Все в Webpack описывается через Loaders. Также ознакомьтесь со скринкастом по нему:

Конечный код будет приложен в конце статьи, чтобы было легче разобраться. Исходным состоянием проекта является проект без JS файлов но с HTML файлом index.

Давайте создадим функцию, которая возвращает компонент. Запомните компоненты всегда называются с большой буквы. Наш назовем Article.js.

import React from 'react'  
   
 function Article() {  
     return (  
         <div>  
             <h1>{ article.title }</h1>  
             <section>{ article body }</section>  
         </div>  
     )  
 }  
   
 export default Article   

Теперь когда компонент описан нужно импортировать его в файле app.js

import { articles } from './fixtures'  
import Article from './Article' // importing the component

Хорошей практикой считается держать по одному файлу на компонент. Т.е. если у Вас 100 компонентов вы будете импортировать 100 компонентов.

Добавим такие строчки в этот же файл

import React from 'react'  
import { render } from 'react-dom'  

В React и Webpack принято использовать NPM для зависимостей. (посмотрите JSON).

Прописываем в Console.

npm I react react-dom –S

Начиная с 14 версии разделили React и React/DOM. Так как появилось множество вещей, которые не зависят от DOM (работа библиотеке на клиенте, сервере, в мобильных приложениях).
В React DOM есть метод для того чтобы отобразить Ваш компонент. Пишем в том же файле.

render(<Article />, document.getElementById('container'))

Какой компонент (Article) и куда его положить. В файле index.html есть div container, в него мы и будем вставлять наш компонент.

<html lang="en">  
<head>  
<meta charset="UTF-8">  
<title>Title</title>  
</head>  
<body>  
<div id="container"></div>  
<script src="/static/bundle.js"></script>  
</body>  
</html>   

В JSON есть webpack-dev-server который позволит запустить наше маленькое приложение с одним компонентом. Зайдем на localhost:8080

webpack-dev-server не собирает физически bundle.js – он хранит Ваши изменения в памяти.

Вернемся к файлу babelrc обратим внимание на:

“react-hmre”. 

Это hot-reloader. Он сохраняет состояния, и без всякой перезагрузки показывает все изменения.

Добавим в app.js в Article какие-нибудь переменные:

render(<Article article = {articles[0]} />, document.getElementById('container'))

Т.е. взяли массив статей из fixtures.js и взяли первую статью. Тут используется новый для нас синтаксис JSX для нас.

{articles[0]} – скобки означают что здесь будет какое-то выражение, какая-то JS переменная. В нашем случае объект articles.

В JSX все что вы передадите таким образом article = {articles[0]}

Будет доступно в вашем компоненте через properties. (props) Оно придет к нам как аргументы.

import React from 'react'  
   
 function Article(props) {
 const articles = props.article
     return (  
         <div>  
             <h1>{ article.title }</h1>  
             <section>{ article.text}</section>  
         </div>  
     )  
 }  
   
 export default Article   

Давайте сделаем компонент articlelist для отображения статей.

Изменим app.js следующим образом

import { articles } from './fixtures'  
import Articlelist from './Articlelist'  
import React from 'react'  
import { render } from 'react-dom'  
  
render(<Articlelist article = {articles} />, document.getElementById('container'))   

В ArticleList.js делаем следующее:

На данный момент весь код в компоненте, написанном на JSX должен быть обернут в корневой элемент (div, например).

import React from 'react'  
import Article from './Article'  
  
function ArticleList(props) {  
    const { articles } = props  
  
    const listItems = articles.map((article) => <li key = {article.id}><Article article = {article}/></li>)  
    return (  
        <div>  
            <h1>Article list</h1>  
            <ul>  
                {listItems}  
            </ul>  
        </div>  
    )  
}  
  
export default ArticleList   

Мы хотим отображать наши статьи, а также переиспользовать уже написанный нами компонент как элемент нашего списка. Т.е. компонент внутри компонента. Для этого импортируем его в наш код как это показано на 2 строчке выше.

Используя map работаем с массивом статей в строчке 7, и превращаем его в массив компонентов. И отображаем его на 12 строчке. В 7 строчке пишем обязательно key, ассоциируя статьи с id чтобы React понимал при создании массива статей где какая, не смешивал их и т.п. Обычно используют ID, но это необязательно, так для этого подойдут любые неповторяющиеся ключи внутри одного массива. Не надо использовать index массивов в виде ключа. Здесь мы создали stateless компоненты, самые простые из возможных, которые получили данные, а затем выполнили их render. В идеале таких компонентов должно быть большинство. Но в реальной жизни необходимо менять и сохранять состояния этих компонентов. В этом случае нужно использовать более сложный синтаксис, такой как классы из ES6.

Следующее что хотелось бы сделать это не отображать все статьи открытыми. Сделаем так чтобы отображались только Заголовки, а при клике на него мы будем видеть всю статью.

В строчке 1 файла Articles.js добавим {Component} на строчке 3 создадим класс, который наследуется от компонента React, где в самом простом случае мы должны описать метод render. Этот метод делает все тоже самое что мы и делали до этого, просто теперь мы описываем это  в нашем методе render. Теперь у нас уже нет аргументов, props входят в this при инициализации компонента props записываются в this. Далее мы будем писать так всегда, когда нам будут нужны более сложные компоненты.  Помимо props у нас есть состояния state (часть es7) на строке 4. Без es7 будет выглядеть как на строке 9. Строка 19 к примеру это тоже самое что и 18, но написана другим способом.

import React, { Component } from 'react'  
  
class Article extends Component {  
    state = {  
        isOpen: false  
    }  
  
/* 
    constructor(props) { 
        super(props) 
        this.state = { 
            isOpen: false 
        } 
    } 
*/  
  
    render() {  
        const article = this.props.article  
//        const { article } = this.props 
//        const { article: { title, text } } = props  
        const { isOpen } = this.state  
        const body = isOpen ? <section>{ article.text }</section> : null  
  
        return (  
            <div>  
                <h1 onClick = {this.toggleOpen}>{ article.title }</h1>  
                {body}  
            </div>  
        )  
    }  
  
    toggleOpen = (ev) => {  
        this.setState({  
            isOpen: !this.state.isOpen  
        })  
    }  
}  
  
  
  
/* 
function Article(props) { 
    const article = props.article 
//    const { article: { title, text } } = props 
 
    return ( 
        <div> 
            <h1>{ article.title }</h1> 
            <section>{ article.text }</section> 
        </div> 
    ) 
} 
*/  
  
export default Article  

На строчках 21 и 22 пишем условия по отображению статей.

Добавим работу с состояниями по клику мыши. Для этого на строке 26 пишем

onClick = {this.toggleOpen}

А на 32 строке описываем работу этой функции. Используем один из важнейших методов React setState. – он вызывает изменение DOM дерева. Эта операция асинхронная. Ваше виртуальное DOM дерево будет перестраиваться с того момента где произошел setState. Для проверки скачайте результаты нашего урока тут.

——————————————————————————————————————————

Домашнее задание – это реализация Comment List, – список комментариев к каждой статье который можно открывать /закрывать по клику на соответствующую ссылку. Текст ссылки должен меняться.

to-be-continued-series-8

We are looking forward to meeting you on our website soshace.com

Уроки React . Урок 9

Всем привет! Сегодня начнем наш урок с домашнего задания, сделав его вместе. Главной целью этих уроков является помочь читателю научиться думать категориями данных – это является основой функционального программирования как такового. когда вы любую систему, например UI, вы описываете набором данных. Пока в наших уроках мы делали все самыми простыми способами. У нас были статьи которые содержат в себе все необходимое, счетчик который содержит в себе число и т.д. Мы пока не делали ничего сложнее, не объединяли все эти элементы, мы не думали какие данные стоит хранить в store а какие в state компонентов. Поэтому давайте все это обсудим. Во-первых, какие данные и где следует держать?

22. Чат Через Long-Polling. Чтение POST. Pt.2.

Соответственно, что бы мы не записали, отправляется одно и то же. Давайте мы это поправим. Сообщения у нас отправляются методом POST. Для того, чтобы считать этот метод из req, нужно поработать с ним, как с потоком. Для этого посмотрим на следующую схему, которая описывает жизненный цикл запроса, а именно объектов req и res.

22. Чат через long-polling, чтение POST. Pt.1.

Всем привет! Цель этого занятия – научиться делать чат на Node.js. Для начала наш чат будет достаточно простой. Всего лишь каждый, кто заходит по этому url

http://localhost:3000/

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

2 Replies to “Уроки React. Урок 1, Введение.”

  1. Владимир 6 years ago

    Здравствуйте! На сегодня актуальный курс?

    1. Никита Брагин 6 years ago

      Статья может быть уже частично устаревшая, была написана на основе онлайн-курсов от 2016 года.

Leave a Reply