Riot.js — это легковесный фронтенд-фреймворк, ориентированный на создание компонентного интерфейса с минимальной абстракцией и высокой производительностью. Ключевым принципом работы с Riot.js является реактивность данных и односторонняя привязка, которые обеспечивают согласованное обновление интерфейса без избыточных перерисовок.
Реактивность в Riot.js строится на наблюдаемых
данных. Любое изменение состояния компонента автоматически
приводит к обновлению DOM, где это состояние используется. Для создания
реактивного свойства в компоненте используется объект
this:
<counter>
<button oncl ick={decrement}>-</button>
<span>{ count }</span>
<button oncl ick={increment}>+</button>
<script>
this.count = 0
this.increment = () => this.count++
this.decrement = () => this.count--
</script>
</counter>
В этом примере переменная count связана с отображением
<span>{ count }</span>. Любое изменение
this.count автоматически обновляет DOM. Riot.js
обеспечивает мгновенную синхронизацию состояния и
интерфейса без явного вызова методов обновления.
Односторонняя привязка данных означает, что поток данных направлен только от модели к представлению. Изменения интерфейса не меняют состояние напрямую, за исключением специальных обработчиков событий. Это позволяет:
Пример:
<task-list>
<ul>
{ this.tasks.map(task => <li>{ task.name }</li>) }
</ul>
<script>
this.tasks = [
{ name: 'Сделать домашнее задание' },
{ name: 'Прочитать документацию' }
]
</script>
</task-list>
Здесь tasks — массив объектов. Любое изменение массива
(например, добавление нового элемента через
this.tasks.push({name: 'Новая задача'})) автоматически
обновляет список <ul>. Данные управляют
интерфейсом, а не наоборот.
Для массивов и объектов Riot.js отслеживает изменения через методы-обертки, которые вызывают повторный рендер компонента:
push, pop, shift,
unshift, splice, sort,
reversethis.update() для ручного обновления при сложных
измененияхПример с динамическим добавлением задачи:
<task-list>
<input ref="newTask" placeholder="Добавить задачу">
<button oncl ick={addTask}>Добавить</button>
<ul>
{ this.tasks.map(task => <li>{ task.name }</li>) }
</ul>
<script>
this.tasks = []
this.addTask = () => {
if (this.refs.newTask.value) {
this.tasks.push({ name: this.refs.newTask.value })
this.refs.newTask.value = ''
}
}
</script>
</task-list>
Вызов push автоматически приводит к обновлению списка
<ul>. Объекты и массивы становятся
реактивными без сложной настройки.
Для примитивов (числа, строки, булевы значения) реактивность
обеспечивается через прямое присваивание
this.property = value. В случае сложных операций над
объектами или вложенными структурами требуется ручное обновление через
this.update().
this.user = { name: 'Иван', age: 25 }
// Изменение вложенного свойства требует обновления компонента
this.user.age++
this.update()
Без вызова this.update() изменение age не
отразится в шаблоне.
Riot.js использует виртуальный DOM на основе парсинга шаблона, что позволяет минимизировать реальные изменения в DOM. Каждое изменение состояния компонента вызывает:
Это обеспечивает высокую производительность при сложных интерфейсах с большим количеством компонентов.
Односторонняя привязка не исключает взаимодействия с пользователем. Все изменения состояния происходят через обработчики событий:
<toggle-switch>
<button oncl ick={toggle}>{ this.active ? 'Включено' : 'Выключено' }</button>
<script>
this.active = false
this.toggle = () => this.active = !this.active
</script>
</toggle-switch>
Состояние active изменяется через метод
toggle, что запускает реактивное обновление
интерфейса. При этом поток данных всегда остаётся от
модели к представлению.
this.{}.Riot.js сочетает минимализм и мощную реактивность, позволяя создавать динамические интерфейсы с предсказуемым управлением состоянием.