Компонентный подход в разработке Blaze фронтенда для MeteorJS приложения

от автора

Целью этой заметки будет объяснение применения изолированных компонент в Blaze фронтендах.
Компонентами я буду называть обособленные части js/html/css кода, не зависящие от глобального состояния или от скрытого состояния внешнего кода, а зависящие только от переменных/реактивных переменных/событий, явно указанных при определении API компонента.

Update в комментариях к англоязычной версии было предложено рассмотреть библиотеку flow-components, которая следует тому же подходу, и базируется на чистом Blaze.


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

Свой последний проект я решил сделать на чистом Meteor. До этого долгое время работал с AngularJS, и выработал там подход, похожий на подход React, где состояние максимально отделено от DOM компонента и максимально явно.
Для этого я использовал директивы и располагал код не по папкам директив/контроллеров/темплейтов, а по папкам для конкретной «фичи» или компонента, как описано в Johnpapa’s Angular Styleguide.

Пробуя воссоздать похожий подход для Blaze, я поставил перед собой цели:

1) Сделать реактивные параметры, которые отправляются в компонент из родительских компонентов при инициализации
2) Реализовать события, которые могут «всплыть» из дочерних компонентов.

В качестве реактивных параметров я использовал отправку ReactiveVars в компонент. Для событий был использован EventEmitter. Использование коллбеков также является возможным вариантом решения.

// client/myTemplate.js 'use strict';  var templateClass = Template.myTemplate;  templateClass.onCreated(function() {     // set initial state     var template = this;     template.data = template.data || {}; // sic! *1     template.state = {         myDualBindingVar: new ReactiveVar('default'), // sic! *2         myEventEmitter: new EventEmitter(),         parentEmitter: template.data.eventEmitter // now I can get parent events     }; });  templateClass.helpers({     myDualBindingVar: function() { // if I want dual binding         return Template.instance().state.myDualBindingVar; // sic! *3     },     myDualBinding: function() { // if I want to just pass this variable in component on initialisation or if I want to draw in in Blaze template of current component         return Template.instance().state.myDualBindingVar.get();     },     eventEmitter: function() {         return Template.instance().state.myEventEmitter;     } }); 

<!-- client/myTemplate.html --> <template name="myTemplate">     <div class="my-template"> <!-- root element with class corresponding to component name -->         {{myDualBinding}}         {{> mySecondTemplate myDualBindingVar=myDualBindingVar eventEmitter=myEventEmitter}}         </div> </template> 

// client/mySecondTemplate.js 'use strict';  var templateClass = Template.mySecondTemplate;  mySecondTemplate.onCreated(function() {     // set initial state     var template = this;     template.data = template.data || {};     template.state = {         myDualBindingVar: template.data.myDualBindingVar,         parentEmitter: template.data.eventEmitter     };     template.autorun(function() {         var myDualBinding = template.state.myDualBindingVar.get();         // do stuff with parent var usage     }); });  mySecondTemplate.events({     'click .someButton': function() {         var emitter = Template.instance().state.parentEmitter;         emitter.emit('someButtonClicked');     } }); 

Объяснение кода выше:

*1: Я пишу template.data = template.data || {}; в каждом компоненте. Причина — если дан 1 или больше параметров, data будет объектом. Если параметров не дано, data будет не пустым объяктом, а null.

*2: ReactiveVar — дополнительный пакет, должен быть установлен отдельно. Я вижу множество туториалов по Метеору, где вместо этого используется Session. Я не рекомендую использовать Session, так как это глобальное состояние. Возникнут дополнительные проблемы, если на странице рисуется больше одного одинакового компонента.

*3: Чтобы получить инстанс темплейта, который используется в данном коде в данный момент, используется вызов на синглтон Template.instance(). Этот подход явно неправильный с точки зрения архитектуры, но я не нашел другого способа это сделать.

За кадром остались другие способы — использование React или Angular для фронтенда. Я опишу их в следующей статье. Скажу только, что в последнее время я перешел на использование React для фронтенда на данном проекте.

Англоязычный вариант моей статьи лежит здесь: loskutoff.com/blog/isolated-blaze-components-in-meteorjs-application/; я не стал добавлять это как перевод, так как довольно сильно изменил некоторые параграфы.

Чем пользуетесь вы для написания фронтенда к Meteor’у?

Проголосовало 46 человек. Воздержалось 11 человек.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

ссылка на оригинал статьи http://habrahabr.ru/post/254347/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *