在polymer里边使用redux

本文主要参考polycast里边一篇介绍在polymer里使用redux的视频教程编写而成,如果感兴趣,可以直接去看原视频(需要科学上网),免得被我误导了。

本文假设你已经了解、接触甚至是使用过polymer/redux这个前端库的前提下进行了。所以如果对polymer/redux这个东西还不了解的话,没关系,我相信勤奋好学的你,会去查阅相关资料的。(还不是因为我懒:-))

什么是redux?

可能你已经听说过、接触过甚至是使用过redux了。嗯,好厉害!我前段时间才开始接触它的,所以写这篇文章的时候,我本人是很虚的,文中有那些不对的地方,欢迎指正。

redux是一个web app的状态管理的库,就算我们不使用redux,我们还是能够写出结构清晰,状态稳定的app。

那么,为什么我们还要使用redux呢?嗯,当然是为了装逼!

举个栗子:

一个班级(web app)需要组织一次活动,组织委员需要统计班上的出行的人员(web components)给老师(state)。但是,有一位同学就在组织委员统计的时候表示说不去了,没空,但是出行的前一天他又改了主意,想去参加活动。但是他没有跟组织委员说,他是直接跟老师说的,但是老师当天有其他急事,没来得及告诉组织委员。结果导致出行的当天,定的车票不够...这下就尴尬了。

上边的栗子可能又许多的漏洞,这里就不一一追究了。但是上边的栗子我们可以看出,出行当天的尴尬在于消息的传递途径不统一:

  • 你可以跟组织委员汇报,然后让组织委员告诉老师;

  • 也可以直接跟老师汇报,但是老师要去联系组织委员定车票的数量;

不统一的通信渠道,导致的状态不同步的问题,就是我们使用redux的主要原因之一。

至于redux是怎么运作的?一些基本概念什么的。这里就不作深究,因为我怕我自己这半桶水会翻车。

需要了解redux的可以点击这里

没有redux的时候

其实,没有redux,polymer本身也是可以编写任何我们需要的功能,只是应用本身的state需要保持警惕,在state需要同步的地方,多下点功夫罢了。类似下图(嫌弃我画的丑的,出门右拐):

polymer-work.jpg

当应用的components数量增多,component内部状态变得复习,比上图复杂的多,state的传递变得很混乱,不好管理,而且如果我们需要在更新状态之后去进行下一项修改状态的时候,这个紧接着的下一个修改的函数就要写成一个回调函数,或者使用promise/generator等方案去解决这件事情了。

事情似乎就变得很复杂,但是使用redux,我们就可以较为轻松的解决这个问题。

redux-work.png

view对应着polymer的web componentview层的变化,通过action指派dispatcherreducer更新全局的唯一的state,更新后的state返回给view层,视图就重新渲染。

所有数据流向都变得简洁明朗。

polymer-redux

polymer-redux是一个别人已经写好了的,将redux封装在内的polymer组件(web component)。没错,我们想要在polymer里边使用redux,就只需要引用它,就行了。会不会很麻烦?我个人感觉挺容易上手的。可能是我用react少吧,我感觉是要要比在react里边使用redux容易上手......

下边我们来写一个简单的例子。该例子主要是来自于polycast里边的Rob Dodson一个讲解polymer-redux的例子,因为我觉得十分的清晰明朗,所以这里就引用一下。(说明一下,我是Rob Dodson的粉丝,如果这里有侵犯他的知识产权的话,我会把这篇文章删了):

该例子主要实现一个添加好友的功能。

  • redux-store: 编写reducer函数,封装成behaviors;

  • friend-counter: 朋友数量计算器,获取friends数组,统计朋友个数;

  • friend-input: 朋友输入器,存在一个inputbutton元素,输入朋友名称以后,点击button之后,将朋友添加到friends数组;

  • friend-list: 朋友列表,接受一个friends数组,将各个元素列出来;

安装依赖

# redux
npm install redux --save

# polymer-redux
bower install polymer-redux --save

index.html

我们在index.html里引入redux.js以及各个组件。(一般来讲,polymer在实际项目使用上应该是使用一个名为xx-app这样子的主组件作为入口,而且polymer官方文档也特别指明这一点的,而不是像下边这样子直接在index.html导入各个组件,直接使用)

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Polymer redux demo</title>
    <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
    <script src="./node_modules/redux/dist/redux.js"></script>
    <link rel="import" href="./bower_components/polymer/polymer.html">
    <link rel="import" href="./src/elements/friend-list.html">
    <link rel="import" href="./src/elements/friend-counter.html">
    <link rel="import" href="./src/elements/friend-input.html">
  </head>
  <body>
    <friend-input></friend-input>
    <friend-counter></friend-counter>
    <friend-list></friend-list>
  </body>
</html>

redux-store.html

首先,我们需要建立一个组件建立应用的store,编写reducer函数。因为reducer本身就是“讲述怎么转换状态”的纯函数,所以在redux-store里边,我们也只是建立reducer函数,然后使用polymer-redux的API——PolymerRedux将reducer封装成一个behaviors就可以了。

<link rel="import" href="../../bower_components/polymer-redux/polymer-redux.html">

<script>
  // 初始化状态
  const initialState = {
    friends: []
  };

  // reducer纯函数
  const reducer = (state, action) => {
    if (!state) {
      return initialState;
    }

    switch (action.type) {
      // 添加好友
      case 'ADD_FRIEND':
        const friends = state.friends.slice(0);
        friends.push(action.friend);
        return Object.assign({}, state, { friends: friends })
    }
  };
  // 建立store
  const store = Redux.createStore(reducer);
  // 封装成polymer behavior
  const ReduxBehavior = PolymerRedux(store);
</script>

friend-counter

引入我们前边封装好的redux-store,使用这个ReduxBehavior,需要注意的是,friend-counter的属性——friends,需要添加一个新的字段:statePath,这里类似于告诉redux,friend-counter的friends属性对应着state的friends

<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="./redux-store.html">

<dom-module id="friend-counter">
  <template>

    <h3>You have [[friendCount]] friends!</h3>

  </template>
  <script>
    Polymer({
      is: 'friend-counter',
      behaviors: [ ReduxBehavior ],
      properties: {
        friends: {
          type: Array,
          statePath: 'friends'
        },
        friendCount: {
          type: Number,
          computed: 'friendCountCompute(friends)'
        }
      },
      friendCountCompute(friends) {
        return friends.length;
      }
    });
  </script>
</dom-module>

friend-input

friend-counter一样,引入redux-store,添加ReduxBehavior。不同的是,这里我们需要触发action,更新状态(state)。

<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="./redux-store.html">

<dom-module id="friend-input">
  <template>

    <input id="input" type="text" />
    <button on-tap="_addFriend" type="button" name="button">Add friend</button>

  </template>
  <script>
    Polymer({
      is: 'friend-input',
      behaviors: [ ReduxBehavior ],
      actions: {
        add: function(name) {
          return {
            type: 'ADD_FRIEND',
            friend: name
          }
        }
      },
      _addFriend() {
        const friend = this.$.input.value;
        if (friend) {
          this.dispatch('add', friend);
        }
      }
    });
  </script>
</dom-module>

friend-list

<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="./redux-store.html">

<dom-module id="friend-list">
  <template>
    <style>
      :host {
        display: block;
      }
    </style>

    <template is="dom-repeat" items="[[friends]]" as="friend">
      <li>[[friend]]</li>
    </template>

  </template>
  <script>
    Polymer({
      is: 'friend-list',
      behaviors: [ ReduxBehavior ],
      properties: {
        friends: {
          type: Array,
          statePath: 'friends'
        }
      }
    });
  </script>
</dom-module>

然后我们来看一下效果图:

friend-app.png

总结一下

  • polymer里边使用redux,方便简单的方法是使用polymer-redux组件,我们可以通过PolymerRedux函数将reducer纯函数封装成polymerbehavior

  • 需要状态同步的组件通过引入该behavior使用redux的一些属性以及行为;

  • 状态同步的属性需要指明statePath

  • 描述"想要去做什么"的actions可以写在该组件内,需要更新状态(state)时,则通过"指派"(dispatch)对应的action;

因为只是学习了一下,暂时还没在实际项目里边使用polymer-redux,所以文中的错漏,还望各位指出。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容