React.js
Библиотека для построения UI-слоя
AKA: V in MVC
Роуты
Модели
Биндинги
Вотчеры
Шаблоны
Разрабатывается инженерами Facebook
В бою на Facebook.com и Instagram.com
How Instagram.com works
React.js
Реализует однонаправленный реактивный поток данных
Проще традиционного дата-биндинга
Key concepts
Компоненты
Шаблоны
Re-render
Мутация
Виртуальный DOM
Синтетические события
View + Template
Шаблоны и логика UI сильно связаны
Имеют одну ответственность
Одна ответственность разделяется на две технологии
и лишнии абстракции
= Component
Spaghetti code!?
Оставляйте свои компоненты небольшими
Link
Многие SPA фреймворки для связи модели с частью UI
используют bindings, observers, templates...
В React есть только состояние
Binding / Observers
Должны мутировать модель для передачи изменений в представление
Каждая мутация может запускать ненужные observers (Run Loop / Digest loop)
React is functional
f(state, props) = UI Fragment
или по-хорошему
f(props) = UI Fragment
-
Идемпотентность
-
Неизменяемость
-
Тестабильность
Re-render на любое изменение
Разработка UI сложна по причине огромного количества состояний
- Много элементов
- Вариантов дизайна
- Непредсказуемое окружение
- Изменяемый DOM
- Пользовательский ввод
- и т.д...
Re-render на любое изменение
Изменение данных причина всех зол
в 90-е было легко
Простое обновление страницы на любое изменение данных
Re-render на любое изменение
Без observers
Без магических дата-биндингов
Без dirty checking моделей
Без $apply() и $digest()
Просто и надежно
Рендер из данных в VDOM быстрый
Нет конкатенации строк
на каждое изменение...
-
Строится новое дерево Virtual DOM
-
Сравнивается со старым
-
Высчитывается кратчайший путь преобразования
-
Добавляется в очередь
-
Пакетный рендер изменений в настоящий DOM
Bonus
Серверный рендер в Node.js, PHP, Java, etc...
Поддержка SVG, VML, Canvas
Синтетические события
React имплементирует собственную событийную систему
Единственный обработчик на корневом компоненте (делегирование)
Нормализирует события между разными браузерами
Отделяет события от DOM
Component code
var Hello = React.createClass({
getInitialState: function() {
return { count: 0 }
},
render: function() {
return React.DOM.div(
{ className: "name", onClick: this.handleClick },
React.DOM.span("Hello, " + this.props.name + "!"),
React.DOM.strong("clicked " + this.state.count + " times")
)
},
handleClick: function() {
this.setState({ count: this.state.count + 1 })
}
})
Возвращаемое значение не является строкой
или DOM нодой, это легковесное описание того, как должен выглядеть DOM.
Component code (JSX)
var Hello = React.createClass({
getInitialState: function() {
return { count: 0 }
},
render: function() {
return <div className="name" onClick={this.handleClick}>
<span>Hello, {this.props.name}!</span>
<strong>clicked {this.state.count} times</strong>
</div>
},
handleClick: function() {
this.setState({ count: this.state.count + 1 })
}
})
JSX легкий сахар который конвертируется в JS
JSX
Доступность шаблонов и сила JavaScript
Делает React более доступным верстальщикам
Composition
var Counter = React.createClass({
render: function() {
if (!this.props.count) return null
return <strong>clicked {this.props.count} times</strong>
}
})
var Hello = React.createClass({
getInitialState: function() {
return { count: 0 }
},
render: function() {
return <div className="name" onClick={this.handleClick}>
<span>Hello, {this.props.name}!</span>
<Counter count={this.state.count} />
</div>
},
handleClick: function() {
this.setState({ count: this.state.count + 1 })
}
})
Render code
React.render(Hello({ name: 'TCS' }), document.body)
response.send(React.renderToString(Hello({ name: 'TCS' })))