博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
More than React(二)组件对复用性有害?
阅读量:5782 次
发布时间:2019-06-18

本文共 4994 字,大约阅读时间需要 16 分钟。

本系列的上一篇文章《》列举了前端开发中的种种痛点。本篇文章中将详细探讨其中“复用性”痛点。我们将用原生 DHTML API 、 ReactJS 和 Binding.scala 实现同一个需要复用的标签编辑器,然后比较三个标签编辑器哪个实现难度更低,哪个更好用。

\\

标签编辑器的功能需求

\\

在InfoQ的许多文章都有标签。比如本文的标签是“binding.scala”、“data-binding”、“scala.js”。

\\

假如你要开发一个博客系统,你也希望博客作者可以添加标签。所以你可能会提供标签编辑器供博客作者使用。

\\

如图所示,标签编辑器在视觉上分为两行。

\\

ddd5b9e43dd071a7739cf8e3cabc5e8a.png

\\

第一行展示已经添加的所有标签,每个标签旁边有个“x”按钮可以删除标签。第二行是一个文本框和一个“Add”按钮可以把文本框的内容添加为新标签。每次点击“Add”按钮时,标签编辑器应该检查标签是否已经添加过,以免重复添加标签。而在成功添加标签后,还应清空文本框,以便用户输入新的标签。

\\

除了用户界面以外,标签编辑器还应该提供 API 。标签编辑器所在的页面可以用 API 填入初始标签,也可以调用 API 随时增删查改标签。如果用户增删了标签,应该有某种机制通知页面的其他部分。

\\

原生 DHTML 版

\\

首先,我试着不用任何前端框架,直接调用原生的 DHTML API 来实现标签编辑器,代码如下:

\\
\\u0026lt;!DOCTYPE html\u0026gt;\\u0026lt;html\u0026gt;\\u0026lt;head\u0026gt;\  \u0026lt;script\u0026gt;\    var tags = [];\\    function hasTag(tag) {\      for (var i = 0; i \u0026lt; tags.length; i++) {\        if (tags[i].tag == tag) {\          return true;\        }\      }\      return false;\    }\\    function removeTag(tag) {\      for (var i = 0; i \u0026lt; tags.length; i++) {\        if (tags[i].tag == tag) {\          document.getElementById(\"tags-parent\").removeChild(tags[i].element);\          tags.splice(i, 1);\          return;\        }\      }\    }\\    function addTag(tag) {\      var element = document.createElement(\"q\");\      element.textContent = tag;\      var removeButton = document.createElement(\"button\");\      removeButton.textContent = \"x\";\      removeButton.onclick = function (event) {\        removeTag(tag);\      }\      element.appendChild(removeButton);\      document.getElementById(\"tags-parent\").appendChild(element);\      tags.push({\        tag: tag,\        element: element\      });\    }\\    function addHandler() {\      var tagInput = document.getElementById(\"tag-input\");\      var tag = tagInput.value;\      if (tag \u0026amp;\u0026amp; !hasTag(tag)) {\        addTag(tag);\        tagInput.value = \"\";\      }\    }\  \u0026lt;/script\u0026gt;\\u0026lt;/head\u0026gt;\\u0026lt;body\u0026gt;\  \u0026lt;div id=\"tags-parent\"\u0026gt;\u0026lt;/div\u0026gt;\  \u0026lt;div\u0026gt;\    \u0026lt;input id=\"tag-input\" type=\"text\"/\u0026gt;\    \u0026lt;button onclick=\"addHandler()\"\u0026gt;Add\u0026lt;/button\u0026gt;\  \u0026lt;/div\u0026gt;\  \u0026lt;script\u0026gt;\    addTag(\"initial-tag-1\");\    addTag(\"initial-tag-2\");\  \u0026lt;/script\u0026gt;\\u0026lt;/body\u0026gt;\\u0026lt;/html\u0026gt;
\\

为了实现标签编辑器的功能,我用了 45 行 JavaScript 代码来编写 UI 逻辑,外加若干的 HTML \u0026lt;div\u0026gt; 外加两行 JavaScript 代码填入初始化数据。

\\

HTML 文件中硬编码了几个 \u0026lt;div\u0026gt;。这些\u0026lt;div\u0026gt; 本身并不是动态创建的,但可以作为容器,放置其他动态创建的元素。

\\

代码中的函数来会把网页内容动态更新到这些 \u0026lt;div\u0026gt; 中。所以,如果要在同一个页面显示两个标签编辑器,id 就会冲突。因此,以上代码没有复用性。

\\

就算用 代替 DHTML API,代码复用仍然很难。为了复用 UI ,jQuery 开发者通常必须额外增加代码,在onload 时扫描整个网页,找出具有特定 class 属性的元素,然后对这些元素进行修改。对于复杂的网页,这些onload 时运行的函数很容易就会冲突,比如一个函数修改了一个 HTML 元素,常常导致另一处代码受影响而内部状态错乱。

\\

ReactJS 实现的标签编辑器组件

\\

ReactJS 提供了可以复用的组件,即 React.Component 。如果用 ReactJS 实现标签编辑器,大概可以这样写:

\\
\class TagPicker extends React.Component {\\  static defaultProps = {\    changeHandler: tags =\u0026gt; {}\  }\\  static propTypes = {\    tags: React.PropTypes.arrayOf(React.PropTypes.string).isRequired,\    changeHandler: React.PropTypes.func\  }\\  state = {\    tags: this.props.tags\  }\\  addHandler = event =\u0026gt; {\    const tag = this.refs.input.value;\    if (tag \u0026amp;\u0026amp; this.state.tags.indexOf(tag) == -1) {\      this.refs.input.value = \"\";\      const newTags = this.state.tags.concat(tag);\      this.setState({\        tags: newTags\      });\      this.props.changeHandler(newTags);\    }\  }\\  render() {\    return (\      \u0026lt;section\u0026gt;\        \u0026lt;div\u0026gt;{\          this.state.tags.map(tag =\u0026gt;\            \u0026lt;q key={ tag }\u0026gt;\              { tag }\              \u0026lt;button onClick={ event =\u0026gt; {\                const newTags = this.state.tags.filter(t =\u0026gt; t != tag);\                this.setState({ tags: newTags });\                this.props.changeHandler(newTags);\              }}\u0026gt;x\u0026lt;/button\u0026gt;\            \u0026lt;/q\u0026gt;\          )\        }\u0026lt;/div\u0026gt;\        \u0026lt;div\u0026gt;\          \u0026lt;input type=\"text\" ref=\"input\"/\u0026gt;\          \u0026lt;button onClick={ this.addHandler }\u0026gt;Add\u0026lt;/button\u0026gt;\        \u0026lt;/div\u0026gt;\      \u0026lt;/section\u0026gt;\    );\  }\\}\
\\

以上 51 行 ECMAScript 2015 代码实现了一个标签编辑器组件,即TagPicker。虽然代码量比 DHTML 版长了一点点,但复用性大大提升了。

\\

如果你不用 ECMAScript 2015 的话,那么代码还会长一些,而且需要处理一些 JavaScript 的坑,比如在回调函数中用不了 this。

\\

ReactJS 开发者可以随时用 ReactDOM.render 函数把 TagPicker 渲染到任何空白元素内。此外,ReactJS 框架可以在state 和 props 改变时触发 render ,从而避免了手动修改现存的 DOM。

\\

如果不考虑冗余的 key 属性,单个组件内的交互 ReactJS 还算差强人意。但是,复杂的网页结构往往需要多个组件层层嵌套,这种父子组件之间的交互,ReactJS 就很费劲了。

\\

比如,假如需要在 TagPicker 之外显示所有的标签,每当用户增删标签,这些标签也要自动更新。要实现这个功能,需要给 TagPicker 传入 changeHandler 回调函数,代码如下:

\\
\class Page extends React.Component {\\  state = {\    tags: [ \"initial-tag-1\

转载地址:http://uvjyx.baihongyu.com/

你可能感兴趣的文章
搭建智能合约开发环境Remix IDE及使用
查看>>
Spring Cloud构建微服务架构—服务消费基础
查看>>
RAC实践采坑指北
查看>>
runtime运行时 isa指针 SEL方法选择器 IMP函数指针 Method方法 runtime消息机制 runtime的使用...
查看>>
LeetCode36.有效的数独 JavaScript
查看>>
Scrapy基本用法
查看>>
PAT A1030 动态规划
查看>>
自制一个 elasticsearch-spring-boot-starter
查看>>
软件开发学习的5大技巧,你知道吗?
查看>>
【人物志】美团前端通道主席洪磊:一位产品出身、爱焊电路板的工程师
查看>>
一份关于数据科学家应该具备的技能清单
查看>>
机器学习实战_一个完整的程序(一)
查看>>
Web框架的常用架构模式(JavaScript语言)
查看>>
如何用UPA优化性能?先读懂这份报告!
查看>>
这些Java面试题必须会-----鲁迅
查看>>
Linux 常用命令
查看>>
NodeJS 工程师必备的 8 个工具
查看>>
CSS盒模型
查看>>
ng2路由延时加载模块
查看>>
使用GitHub的十个最佳实践
查看>>