Я очень заинтересовался Полимером с тех пор, как начал работать по новому контракту с Toaster. В последний раз я смотрел на него перед тем, как это было впервые объявлено. Я помню, как в то время я был увлечен Angular, и когда я сравнил то, с чем был запущен и предлагал Polymer, меня это не впечатлило, но времена изменились!

Однако одним из аспектов, которые мне действительно понравились и которые я получил в Angular, были его сервисы / фабрики. Чтобы сохранить состояние для приложения, такого как классическое приложение для задач, у вас будет TodoService, в котором хранятся все задачи, а также методы для применения к ним изменений и их чтения. Если вы хотите получить текущие задачи, вы, например, выполните вызов TodoService.getCurrentTodos ().

С Полимером у вас нет услуг, по крайней мере, не в углах. У вас действительно есть подобные идеи с самими встроенными железными элементами, например, iron-request. Если вы хотите выполнить запрос ajax в своем компоненте, выполните следующие действия:

<template>
  <iron-request id="request"></iron-request>
</template>
<script>
  Polymer({
    is: 'my-element',
    doRequest: function(){
      this.$.request.generateRequest()
    }
  });
</script>

Это достаточно просто сделать, и кажется, что это очень похоже на веб-компоненты или полимеры. Однако когда дело доходит до управления состоянием в средне- и крупномасштабном приложении, вы сталкиваетесь с проблемами.

Если у вас есть глубоко вложенные компоненты, которым нужны данные о состоянии, обычно вам придется делать то, что вы должны были делать в React, когда он только начинал работать: вам нужно было бы найти ближайший общий предок и сохранить состояние, а также убедитесь, что вы передаете его через все компоненты, пока не дойдете до тех, которые нуждаются в состоянии. Это не очень хорошо, и перемещение компонентов обходится дорого, поскольку вам нужно переписывать код. Структура и макет приложения тесно связаны с реализацией ваших данных и местом их размещения.

Решение

Я думал о нескольких способах справиться с этим и в итоге пришел к следующему. Он вдохновлен подходом Flux / Redux (ish) в том, что вы сохраняете все свое состояние в большом глобусе (или атоме, если вы переходите к Om), а затем читаете и записываете его отдельно, но никогда из того же компонента. Это всего лишь набор из трех разных моделей поведения, и на данный момент он очень прост, это только начало.

Всего 64 строки, и это облегчит вам жизнь. Идея состоит в том, что у вас будет компонент верхнего уровня (верхний уровень и как можно раньше в DOM, чтобы он был инициализирован первым), и этот компонент (вероятно, называемый app-state) будет использовать StateProviderBehavior, что-то вроде следующего.

<script>
  Polymer({
    is: 'app-state',
    properties: {
      state: {
        type: Object,
        value: {
          text: 'initial value'
        }
      }
    },
    behaviors: [StateProviderBehavior]
 });
</script>

Он объявляет все состояние, которое вы хотите сохранить в своем приложении, это то, куда будет идти Todos; где имя пользователя будет для текущего пользователя или что-то в этом роде.

Затем вы можете подключить все элементы, которые нужно отобразить из глобального состояния, к StateReceiverBehaviour, как показано ниже.

<script>
  Polymer({
    is: 'todo-list',
    properties: {
      text: {
        linkState: 'state.text'
      }
    },
    behaviors: [StateReceiverBehavior]
 });
</script>

В приведенном выше элементе всякий раз, когда происходит изменение в элементе app-state вложенного свойства «text», компонент todo-list будет иметь значение его свойства text, установленное на новое значение. Следует отметить, что этот элемент должен быть доступен только для чтения, вы не должны писать в него из этого элемента, он будет переопределен любыми значениями, установленными в вашем глобальном состоянии.

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

<script>
  Polymer({
    is: 'todo-service',
    behaviors: [StateWriterBehavior],
    fetchTodos: function(){
      doAsyncAjaxFetchRequest(function(successResult){
        var someComputedValue = this.getState().get('state.text');
        this.getState().set('state.text', someComputedValue);
      }.bind(this));
    }
  });
</script>

Как видите, при установке состояния в компоненте глобального состояния вы должны использовать обычные установщики Polymer, в том числе следующее:

  • установленный
  • толкать
  • не сдвигать
  • сращивание
  • notifyPath

Вероятно, есть еще один или два других, которые я пропустил, но важная часть заключается в том, что вы используете способ Polymer для установки состояния в компоненте состояния приложения - это вызовет зарегистрированный наблюдатель ('_stateChanged' внутри StateProviderBehavior), который будет инициировать обновление локального состояния всех связанных элементов StateReceiverBehavior.

Почему нет двусторонней привязки

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

Если двусторонняя привязка была включена для всего состояния приложения, и читатели могли обновлять свои локальные копии значения и возвращать их в глобальное состояние, легко могли возникнуть циклические зависимости. Это похоже на проблемы, которые вы использовали в Backbone и т. Д., Когда у вас были бы сигналы, срабатывающие повсюду, и отслеживание ошибок быстро превратилось бы в кошмар.

Именно по этой причине - здравомыслие - StateReaderBehavior и StateWriterBehavior должны быть взаимоисключающими.

Единственный случай, когда чтение и запись в глобальное состояние разрешены, - это внутри ваших компонентов службы. Поскольку у них в любом случае есть доступ к состоянию через метод getState (), и они могут записывать состояние, вполне вероятно, что им тоже нужно будет его прочитать, скажем, чтобы обновить список дел и установить действия или что-то еще. Службы также не обновляют изменения своих собственных свойств с помощью модификатора свойства linkState; они должны вручную получить состояние, когда они хотят получить новое значение.

Заключение

Это не идеальное решение, но оно очень простое и, как я считаю, может вам очень пригодиться для средних и крупных приложений. Вы можете свободно перемещать свои компоненты по своему усмотрению (при условии, что состояние приложения определено на ранней стадии и высоко в дереве DOM), и вы получаете хорошее разделение поведения, изменяющего глобальное состояние. Вы также получаете неизменные значения. Итак, ваше фактическое состояние не является неизменным, но поскольку значения элементов прослушивателя состояния полностью перезаписаны, их значения состояния по существу неизменны.

Попробуй, крикни с любыми мыслями.