美文网首页
在polymer里边使用redux

在polymer里边使用redux

作者: classlfz | 来源:发表于2017-03-05 22:02 被阅读210次

    本文主要参考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,所以文中的错漏,还望各位指出。

    相关文章

      网友评论

          本文标题:在polymer里边使用redux

          本文链接:https://www.haomeiwen.com/subject/dwwegttx.html