React как беспилотный автомобиль

DataArt (2010-2011)
Stampsy (2012-2015)

?

Даниил Абрамов

Dan Abramov

Stampsy for iPad

Stampsy.com

twitter/dan_abramov

github/gaearon

Зачем рендерить на клиенте?

  • Где-то рендерить надо

  • Дублировать UI-код непрактично

  • Стоимость фич не должна прыгать

  • Всё равно надо делать API

  • Есть срединный путь

  • MVC, MVP, MVVM, MVI, MMXV, MMM ...

  • Фабрики локаторов сервисов фабрик

  • Двусторонняя привязка данных
     

  • Мешать разметку с кодом

  • Инлайновые стили

  • Инлайновые обработчики событий

Лучшие Практики

Лучшие Практики

Лучшие Практики

Лучшие Практики

Лучшие Практики

Лучшие Практики

Почему веб-приложение это сложно?

Почему приложение это сложно?

Данные

Интерфейс

v
v
m
m

Global Events

Dirty Checking

Data Binding

Lifecycle

Routing

Persistence

Networking

Transactions

Animations

change:text

router:navigate

...

$(el).text()

app.replaceChildView()
...

\Delta_v = f(\Delta_m)
Δv=f(Δm)

change:text

router:navigate

...

$(el).text()

app.replaceChildView()
...

\Delta_v = f(v, \Delta_m)
Δv=f(v,Δm)
_v
v
v
v
\Delta
Δ
, \Delta_m)
,Δm)
= f(
=f(
v
v
v'
v
v''
v
v'''
v
v''''
v
v
v
v'
v
v''
v
v'''
v
v''''
v
N \times (N - 1)
N×(N1)
O(N^2)
O(N2)

Сложность кода для обновления UI растет как квадрат количества его состояний

v
v
v'
v
v''
v
v'''
v
v''''
v
:(
:(
_v
v
v
v
\Delta
Δ
, \Delta_m)
,Δm)
= f(
=f(

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

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

v = f(m)
v=f(m)
v
v
v'
v
v''
v
v'''
v
v''''
v
v'''''
v

Если UI это функция, что она возвращает?

Элемент DOM?

Строку?

Промежуточное представление!

Декларативное описание UI

И в чем разница?

_v
v
v
v
\Delta
Δ
, \Delta_m)
,Δm)
= f(
=f(
v = f(m)
v=f(m)

Virtual DOM

Value DOM?

UI первого класса

Привычные средства абстракции

Компоненты

Функции

Свойства — единственный API компонента

React.render и this.setState()

Разработчик

  • Как преобразовать данные в UI?
  • Как события из UI изменяют данные?
  • Как разбить UI на независимые компоненты?

React

  • Как эффективно перейти от одного UI-дерева к другому?
v
v
v'
v
v''
v
v'''
v
v''''
v
v'''''
v

Интересные следствия

Малая поверхность API

Предсказуемость

Рендеринг не в DOM

Сохранение и восстановление состояния

Горячая загрузка

Нет «смерти от тысячи порезов»

Свобода от DSL

JSX?

Но это же DSL?

А как же разделение ответственности?

Что мы узнали

  • Описывать динамические процессы сложно
  • Описывать N*(N–1) переходов трудоемко
  • Проще описывать статические «снимки» UI
  • UI первого класса дает гибкость
  • Баги будут — важна предсказуемость

Что мы узнали

  • Чтобы знать React, надо знать JavaScript
  • React это V, но «толстые» M и C не нужны
  • React может работать в разных окружениях
  • Можно использовать JSX
  • Используется в продакшне Facebook, Airbnb, Reddit, Codecademy, Flipboard, Khan Academy, Yahoo, ...

Демо

Архитектура

Цель: Предсказуемость

Цель: Предсказуемость

Цель: Консистентность

Цель: Консистентность

Лучше, если данные «живут» где-то сверху и передаются вниз

MVC?

  • Гранулярные изменения не нужны

  • Есть механизм передачи данных вниз

  • Отлично сочетается с неизменяемостью

Сильные стороны React

  • Непредсказуемые каскадные обновления

  • Не сочетается с неизменяемостью

  • Сложно работать с циклическими и глубоко вложенными данными

Слабые стороны MVC

Flux

Global Events

Dirty Checking

Data Binding

Lifecycle

Routing

Persistence

Networking

Transactions

Animations

Global Events

Dirty Checking

Data Binding

Lifecycle

Routing

Persistence

Networking

Transactions

Animations

Компоненты

Данные

Как отвязать компоненты от знаний о внутренней структуре данных?

Промежуточное представление!

Не записывай,
а описывай.

{
  type: "follow_user",
  userId: 123
}

Хранилища

Компоненты

Действие

Изменение данных

Хранилища нельзя изменить напрямую

Store.getSomething()

Store.setSomething()

{
  type: "follow_user",
  userId: 50
}

Хранилища

Компоненты

Действие

Изменение данных

{
  type: "like_post",
  postId: 42
}

Хранилища

Компоненты

Действие

Изменение данных

{
  type: "follow_user",
  userId: 227
}

Хранилища

Компоненты

Действие

Изменение данных

Нет каскадов изменений

Много ко многим

Хранилища

Компоненты

Обновление UI

"changed"

Хранилища

Компоненты

Обновление UI

"changed"

Гранулярность на уровне хранилищ

Подписываться лучше выше и мало

Хранилища

Компоненты

Хранилища

Компоненты

{
  type: "follow_user",
  userId: 123
}

Хранилища

Компоненты

Действие

Трансляция действия компонентом

{
  type: "follow_user",
  userId: 123
}

Хранилища

Компоненты

Действие

Изменение данных хранилищами

Хранилища

Компоненты

Оповещение компонентов

Хранилища

Компоненты

"changed"

Оповещение компонентов

Хранилища

Компоненты

Обновление компонентами состояния

Хранилища

Компоненты

Обновление компонентами состояния

Хранилища

Компоненты

AJAX?

Все данные должны приходить из действий

Все изменения должны быть заключены в хранилищах

m_n = f(m_{n-1}, action)
mn=f(mn1,action)
m_n = f(m_0, actions)
mn=f(m0,actions)

Интересные свойства

Предсказуемость

Предсказуемость

Запись и вопроизведение

Нормализация

Кросс-платформенность

Когда использовать Flux?

twitter/dan_abramov

github/gaearon

Made with Slides.com