Специфика использования Redux в Polymer и Vue +4



Как я уже писал в своих предыдущих статьях я работал и с polymer и с vue в связке с redux. Поэтому хотелось бы поделиться опытом, связанным со спецификой использования redux в данных библиотеках. Рассматривать будем на простейших атомарных контролах: нативных (input, checkbox) и обернутых, в виде компонентов данных библиотек.

В статье я опуская описание настройки интеграции redux с polymer и vue, а так же описание азов самого redux, дабы не эту тему хочу раскрыть в статье.

0. Введение


Сначала вспомним один из основных принципов redux:
The only way to change the state is to emit an action, an object describing what happened.

Исходя из него ясно, что напрямую мы не можем изменить состояние, а сделать это можем только через диспатч экшена после наступление необходимого event'а.

Схематично это можно изобразить так:

Как видим наблюдается односторонний поток данных.

1. Нативные контролы


polymer


Очень удобная вещь в polymer при связке с redux дак это односторонний биндинг.

template:

<input value="[[propFromReduxStore]]" on-change="changeText"></input>

js-code:

changeInput: function(e) {
  this.dispatch("setText", e.currentTarget.value);
}

Поэтому с input все, в принципе стандартно: при событии change диспатчим action и после чего измененное значение попадает в propFromReduxStore и контрол перерендерится уже с новым значением.

vue


C vue немного другая ситуация, в нем нет как такагого одностороннего биндинга, как в polymer. Но подобную функциональность можно достигнуть через модификатор sync

UPD: Спасибо mayorovp за наводку: на самом деле никакой .sync не нужен. По поводу биндинга: v-model дает двусторонний биндинг, а как раз :value — односторонний. Поэтому в примере ниже не нужен .sync.
template:

Старый код
<input :value.sync="propFromReduxStore" @change="changeText"></input>


<input :value="propFromReduxStore" @change="changeText"></input>


js-code:

changeInput: function(e) {
  this.actionsRedux("setText", e.currentTarget.value);
}

Остальное все как и в варианте с polymer.

2. Компоненты


С компонентами сложней, так как это совокупность методов, событий, «завернутые» в компоновку html-элементов в виде шаблона.

Схематичное описание работы компонента:

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

polymer


На примере компонента paper-checkbox

template:

<paper-checkbox checked="[[propFromReduxStore]]" on-tap="changeCheck"></paper-checkbox>

js-code:

changeCheck: function(e) { //Здесь ловим клик по компоненту
  //Предотвращаем bubbling события, что бы компонент сразу не перерендерил компонент 
  e.stopPropagation();
  this.dispatch("setChecked", !this.propFromReduxStore);
}

vue


На примере компонента el-checkbox

template:

UPD: Код ниже подчеркивает сам подход через нативные ивенты, но для конкретного контрола(имеется в виду его внутренняя архитектура) имеет место три вариант:

  <el-checkbox :value="checked" @change="changeCheck">
  </el-checkbox>
  <el-checkbox :value="checked" @click.prevent.stop.native="changeCheck">
  </el-checkbox>
  <el-checkbox v-model="checked" @click.prevent.stop.native="changeCheck">
  </el-checkbox>

Старый вариант
<el-checkbox v-model="propFromReduxStore" @click.stop.native="changeCheck" >
</el-checkbox>


js-code:

changeCheck: function() {
  this.actionsRedux("setChecked", !this.propFromReduxStore);
}

В компоненте может даже и не быть события click, а если и есть, то узнаем мы об его наступлении уже постфактум, не говоря уже об его подалении, но зато есть модификатор native, который позволяет получить доступ ко всем возможным нативным событиям. Так же есть модификатор stop и prevent, который даже позволит нам не писать e.stopPropagation() и e.preventDefault(), как это было с polymer. Малость, а приятно.
Вся суть в том: что при необходимости, мы можем получить доступ к нативным событиям компонента и полностью их подавить, и пустить data-workflow по нужному нам пути.

React не рассмотрел, так как на практике его не использовал, если не считать jsx-темплейтов в vue, но это совершенно не то. Но все-таки, насколько я наслышен от коллег по цеху, там таких проблем нет, в виду внутренней архитектуры обработки событий.




К сожалению, не доступен сервер mySQL