Передача данных между компонентами

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


Передача данных через атрибуты

Наиболее прямой способ передачи данных в Riot — использование атрибутов компонента при его включении в родительскую разметку. Атрибуты становятся свойствами компонента и доступны через объект props.

// Компонент child.riot
<child name={props.name}>
  <p>Привет, {props.name}!</p>
</child>
// Родительский компонент parent.riot
<parent>
  <child name="Иван"></child>
</parent>

Ключевые моменты:

  • Атрибуты передаются только сверху вниз (от родителя к потомку).
  • Значения могут быть как статическими, так и динамическими (связанными с состоянием родителя).
  • Изменения в родителе не обновляют автоматически свойства дочернего компонента, если не используются реактивные ссылки на props.

Использование событий для обратной связи

Для передачи данных от дочернего компонента к родительскому применяются кастомные события. В Riot.js компоненты могут вызывать события через метод this.trigger:

// child.riot
<child>
  <button oncl ick={sendData}>Отправить</button>

  <script>
    export default {
      sendData() {
        this.trigger('dataSent', { message: 'Привет из дочернего компонента' });
      }
    }
  </script>
</child>
// parent.riot
<parent>
  <child ondataS ent={handleData}></child>

  <script>
    export default {
      handleData(event) {
        console.log(event.message);
      }
    }
  </script>
</parent>

Особенности:

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

Использование общих состояний и стор

Для более сложных приложений с большим числом компонентов удобно использовать общее состояние (store). Riot.js поддерживает реактивные объекты, которые могут быть подписаны несколькими компонентами.

// store.js
import { observable } from 'riot';

export const store = observable({
  count: 0,
  increment() {
    this.count += 1;
    this.trigger('update');
  }
});
// component.riot
<counter>
  <p>Счетчик: {store.count}</p>
  <button oncl ick={increment}>+</button>

  <script>
    import { store } from './store.js';
    export default {
      onBeforeMount() {
        store.on('update', () => this.update());
      },
      increment() {
        store.increment();
      }
    }
  </script>
</counter>

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

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

Контекст и вложенные компоненты

Riot.js позволяет передавать данные через контекст компонента, что удобно для deeply nested компонентов. Контекст создается с помощью объекта opts и передается при вызове дочернего компонента.

// parent.riot
<parent>
  <child {opts}></child>

  <script>
    export default {
      opts: { theme: 'dark', language: 'ru' }
    }
  </script>
</parent>

В дочернем компоненте доступ к контексту осуществляется через props:

// child.riot
<p>Тема: {props.theme}, Язык: {props.language}</p>

Особенности:

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

Связка с реактивными выражениями

Riot.js поддерживает реактивные выражения внутри шаблонов. С помощью них можно передавать данные и автоматически обновлять DOM при изменении состояния:

<parent>
  <child name={name}></child>
  <input onin put={e => this.name = e.target.value} value={name}>
  <script>
    export default {
      name: 'Иван'
    }
  </script>
</parent>

Ключевые моменты:

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

Практические рекомендации

  • Для простых данных использовать атрибуты и события.
  • Для глобального состояния применять observable store.
  • Для передачи настроек или конфигураций — контекст через opts.
  • Всегда учитывать однонаправленную природу передачи данных: родитель → потомок через props, потомок → родитель через события.
  • Комбинировать методы передачи данных в сложных приложениях для поддержания читаемости и модульности кода.