BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

More than React(二)组件对复用性有害?

| 作者 杨博 关注 3 他的粉丝 发布于 2016年9月1日. 估计阅读时间: 25 分钟 | GMTC大前端的下一站,PWA、Web框架、Node等最新最热的大前端话题邀你一起共同探讨。

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

标签编辑器的功能需求

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

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

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

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

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

原生 DHTML 版

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

<!DOCTYPE html>
<html>
<head>
  <script>
    var tags = [];

    function hasTag(tag) {
      for (var i = 0; i < tags.length; i++) {
        if (tags[i].tag == tag) {
          return true;
        }
      }
      return false;
    }

    function removeTag(tag) {
      for (var i = 0; i < 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 && !hasTag(tag)) {
        addTag(tag);
        tagInput.value = "";
      }
    }
  </script>
</head>
<body>
  <div id="tags-parent"></div>
  <div>
    <input id="tag-input" type="text"/>
    <button onclick="addHandler()">Add</button>
  </div>
  <script>
    addTag("initial-tag-1");
    addTag("initial-tag-2");
  </script>
</body>
</html>

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

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

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

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

ReactJS 实现的标签编辑器组件

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

class TagPicker extends React.Component {

  static defaultProps = {
    changeHandler: tags => {}
  }

  static propTypes = {
    tags: React.PropTypes.arrayOf(React.PropTypes.string).isRequired,
    changeHandler: React.PropTypes.func
  }

  state = {
    tags: this.props.tags
  }

  addHandler = event => {
    const tag = this.refs.input.value;
    if (tag && 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 (
      <section>
        <div>{
          this.state.tags.map(tag =>
            <q key={ tag }>
              { tag }
              <button onClick={ event => {
                const newTags = this.state.tags.filter(t => t != tag);
                this.setState({ tags: newTags });
                this.props.changeHandler(newTags);
              }}>x</button>
            </q>
          )
        }</div>
        <div>
          <input type="text" ref="input"/>
          <button onClick={ this.addHandler }>Add</button>
        </div>
      </section>
    );
  }

}

以上 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", "initial-tag-2" ]
  };

  changeHandler = tags => {
    this.setState({ tags });
  };

  render() {
    return (
      <div>
        <TagPicker tags={ this.state.tags } changeHandler={ this.changeHandler }/>
        <h3>全部标签:</h3>
        <ol>{ this.state.tags.map(tag => <li>{ tag }</li> ) }</ol>
      </div>
    );
  }

}

为了能触发页面其他部分更新,我被迫增加了一个 21 行代码的 Page 组件。

Page 组件必须实现 changeHandler 回调函数。每当回调函数触发,调用 Page 自己的 setState 来触发 Page 重绘。

从这个例子,我们可以看出, ReactJS 可以简单的解决简单的问题,但碰上层次复杂、交互频繁的网页,实现起来就很繁琐。使用 ReactJS 的前端项目充满了各种 xxxHandler 用来在组件中传递信息。我参与的某海外客户项目,平均每个组件大约需要传入五个回调函数。如果层次嵌套深,创建网页时,常常需要把回调函数从最顶层的组件一层层传入最底层的组件,而当事件触发时,又需要一层层把事件信息往外传。整个前端项目有超过一半代码都在这样绕圈子。

Binding.scala 的基本用法

在讲解 Binding.scala 如何实现标签编辑器以前,我先介绍一些 Binding.scala 的基础知识:

Binding.scala 中的最小复用单位是数据绑定表达式,即 @dom 方法。每个 @dom 方法是一段 HTML 模板。比如:

// 两个 HTML 换行符
@dom def twoBr = <br/><br/>
// 一个 HTML 标题
@dom def myHeading(content: String) = <h1>{content}</h1>

每个模板还可以使用bind语法包含其他子模板,比如:

@dom def render = {
  <div>
    { myHeading("Binding.scala的特点").bind }
    <p>
      代码短
      { twoBr.bind }
      概念少
      { twoBr.bind }
      功能多
    </p>
  </div>
}

你可以参见附录:Binding.scala快速上手指南,学习上手Binding.scala开发的具体步骤。

此外,本系列第四篇文章《HTML也可以编译》还将列出Binding.scala所支持的完整HTML模板特性。

Binding.scala实现的标签编辑器模板

最后,下文将展示如何用Binding.scala实现标签编辑器。

标签编辑器要比刚才介绍的HTML模板复杂,因为它不只是静态模板,还包含交互。

@dom def tagPicker(tags: Vars[String]) = {
  val input: Input = <input type="text"/>
  val addHandler = { event: Event =>
    if (input.value != "" && !tags.get.contains(input.value)) {
      tags.get += input.value
      input.value = ""
    }
  }
  <section>
    <div>{
      for (tag <- tags) yield <q>
        { tag }
        <button onclick={ event: Event => tags.get -= tag }>x</button>
      </q>
    }</div>
    <div>{ input } <button onclick={ addHandler }>Add</button></div>
  </section>
}

这个标签编辑器的 HTML 模板一共用了 18 行代码就实现好了。

标签编辑器中需要显示当前所有标签,所以此处用tags: Vars[String]保存所有的标签数据,再用for/yield循环把tags中的每个标签渲染成UI元素。

Vars 是支持数据绑定的列表容器,每当容器中的数据发生改变,UI就会自动改变。所以,在x按钮中的onclick事件中删除tags中的数据时,页面上的标签就会自动随之消失。同样,在Add按钮的onclick中向tags中添加数据时,页面上也会自动产生对应的标签。

Binding.scala不但实现标签编辑器比 ReactJS 简单,而且用起来也比 ReactJS 简单:

@dom def render() = {
  val tags = Vars("initial-tag-1", "initial-tag-2")
  <div>
    { tagPicker(tags).bind }
    <h3>全部标签:</h3>
    <ol>{ for (tag <- tags) yield <li>{ tag }</li> }</ol>
  </div>
}

只要用 9 行代码另写一个 HTML 模板,在模板中调用刚才实现好的 tagPicker 就行了。

完整的 DEMO 请访问 https://thoughtworksinc.github.io/Binding.scala/#4

在 Binding.scala 不需要像 ReactJS 那样编写 changeHandler 之类的回调函数。每当用户在 tagPicker 输入新的标签时,tags 就会改变,网页也就会自动随之改变。

对比 ReactJS 和 Binding.scala 的代码,可以发现以下区别:

  • Binding.scala 的开发者可以用类似 tagPicker 这样的 @dom 方法表示 HTML 模板,而不需要组件概念。
  • Binding.scala 的开发者可以在方法之间传递 tags 这样的参数,而不需要 props 概念。
  • Binding.scala 的开发者可以在方法内定义局部变量表示状态,而不需要 state 概念。

总的来说 Binding.scala 要比 ReactJS 精简不少。

如果你用过 ASP 、 PHP 、 JSP 之类的服务端网页模板语言,
你会发现和 Binding.scala 的 HTML 模板很像。

使用 Binding.scala 一点也不需要函数式编程知识,只要把设计工具中生成的 HTML 原型复制到代码中,然后把会变的部分用花括号代替、把重复的部分用 for / yield 代替,网页就做好了。

结论

本文对比了不同技术栈中实现和使用可复用的标签编辑器的难度。

Binding.scala 不发明“组件”之类的噱头,而以更轻巧的“方法”为最小复用单位,让编程体验更加顺畅,获得了更好的代码复用性。

本系列下一篇文章将比较 ReactJS 的虚拟 DOM 机制和 Binding.scala 的精确数据绑定机制,揭开 ReactJS 和 Binding.scala 相似用法背后隐藏的不同算法。

相关链接

More than React 系列文章

《More than React(一)为什么ReactJS不适合复杂交互的前端项目?》

《More than React(二)组件对复用性有害?》

《More than React(三)虚拟DOM已死?》

《More than React(四)HTML也可以静态编译?》

《More than React(五)异步编程真的好吗?》

作者简介

杨博是 Haxe 和 Scala 社区的活跃贡献者,发起和维护的开源项目包括 protoc-gen-as3Stateless Futurehaxe-continuationFastringEachMicrobuilderBinding.scala 。杨博曾在网易任主程序和项目经理,开发过多款游戏。现在ThoughtWorks任Lead Consultant,为客户提供移动、互联网、大数据、人工智能和深度学习领域的解决方案。


感谢张凯峰对本文的策划,韩婷对本文的审校。

给InfoQ中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家通过新浪微博(@InfoQ@丁晓昀),微信(微信号:InfoQChina)关注我们。

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

水水水 by 张 同学

这篇真的是太水了。
为了推广自己的项目,而去把其他项目贬得一无是处,有必要吗?
而且还是用这么没有说服力的方式,一定要在一个小的功能点上通过比较代码行数来得出结论吗?

Re: 水水水 by Yang Bo

我不知道怎么回复您的问题。我作为源码级咨询师,不比代码还能比什么?

您可能觉得这个功能点比较小,但这样的日常前端开发需求还是挺常见的。

可能您没有读完整篇文章,所以您觉得我把ReactJS贬得一无是处。但如果您读完了,您就会发现React.Component相比过去用jQuery和原生DHTML,复用性其实是更好的。

希望您在读完文章之后,能给我一些具体一点的反馈。我挺担心大家觉得我写的 ReactJS 代码不地道。您可以帮我看一下。

Re: 水水水 by 张 同学

如果在实际项目中,真的每个Component都独自管理state,要靠众多的回调才能相互通信的话,那么确实会是地狱。
但是现在flux或者redux之类的全局单一状态管理,几乎已经公认是React的最佳实践了,这时候在忽略了这些的前提下,用最手工的方法写一些代码,就说React会有回调地狱,不是太合适吧。

而且还用了『笨重』、『噱头』之类的字眼,着实会有点扎眼。也会让一些不了解细节的新人,脑中留下了这个印象就走了。

Re: 水水水 by liu channing

Component之间数据通讯方式“不爽”,应该不能归结于React本身,还有Flux、Redux等用于处理数据流的问题。
而这文章里面,恕我水平有限,我也没有看出React组件对复用性的负面影响。
另外,也有声音说组件化的目的是“分治”,而不是“复用”。但我觉得分治、复用都是我的目标。
如果本文能把重点放在“复用性”问题中,会更加清晰明了。

Re: 水水水 by Yang Bo

您说得对,用 Binding.scala 和 ReactJS 对比,对 ReactJS 太不公平了。毕竟 ReactJS 只有 View 层的功能,而 Binding.scala 则是完整的前端解决方案。

欢迎您提供一些 Flux 或者 Redux 的例子,和 Binding.scala 对比。

Re: 水水水 by Yang Bo

您好,我并没有用“笨重”这个字眼啊。

当然 ReactJS 的代码量是 Binding.scala 的三倍多,新人确实很容易留下“ReactJS很笨重”的印象。

都怪我把 Binding.scala 设计得太简洁了。对不起。

Re: 水水水 by Yang Bo

其实我挺理解您的想法,因为您可能以前用 Angular 或者 jQuery 比较多,所以 ReactJS 组件相比之下还算简洁,复用起来还算容易。

不过本文介绍的 Binding.scala 可能比 ReactJS 还要简单一点。具体在本文的例子中, ReactJS 例子中三分之二的代码都是多余的,是 Component 带来的语法噪音。

其实现代语言都属于结构化编程语言,函数和类本身就是基本复用单位,并不需要额外发明 Component 这个概念。

Re: 水水水 by Yang Bo

您二位都提到了 Flux 和 Redux 。这两个框架恐怕语法噪音更多。

如果说 Binding.scala 能够“简单实现简单交互”+“简单实现复杂交互”, ReactJS 是 “简单实现简单交互”+“复杂实现复杂交互” ,那么 Flux 和 Redux 恐怕是 “复杂实现简单交互”+“复杂实现复杂交互” 。

比如本例中的 tagPicker , Binding.scala 的例子用了 17 行代码,ReactJS 用了 51 行,Flux 和 Redux 实现的话,我估计会比 ReactJS 还要长。

值得支持的项目 by 夏 鹏

恰好我现在在用React做大型项目。仅仅从React来讲,局限性蛮大的,要想在项目中用React,基本上得选择React的整个技术栈,比如redux、react route等等,要学好多东西才能做出一个项目来。React的数据单向流动,的确在一些复杂的地方需要在外层组件传入一些函数回调,这个在很多时候也的确觉得是个麻烦事情。不过我倒是喜欢React这种打破传统的思想的。从我刚最初接触HTML的时候,对于CSS和JS都要用单独的外部文件去组织的方式不太爽,React这种思维想法对我来说是蛮爽的。

对于国人能做出Binding.scala框架,在我看来是很值得支持的,能够看到国人在技术方面独树一帜的太少了。不过对于我来说Binding.scala阻止我去使用的地方不是别的,而是scala语言,又得去学新的语言,对于前几年几乎呕心沥血学了差不多十来种语言,做了无数乱七八糟的项目,好不容易静下心来选定一个方向准备往高处攀登的时候,想起还要再去从头学别的语言,心里有万匹草泥马奔腾啊。

不过推荐其他同学详细了解和支持。

Re: 水水水 by 张 同学

既然你坚持数着代码行数来比优劣,那么React永远都不可能赢。
不过要是用Vue.js的话,可能会比你的代码更少,不知道你怎么看?

多说无益了。
就我个人来说,小项目用Vue.js,大项目用React.js,暂时应该对Scale写前端没什么兴趣。

Re: 水水水 by Yang Bo

暂时应该对Scale写前端没什么兴趣。

我觉得您最好别用 Scala 。因为对于 Scala 这种静态类型语言来说,如果您喜欢写错别字的话,是没办法通过编译的。

Re: 值得支持的项目 by Yang Bo

我理解你对技术投资的万马奔腾心情,毕竟自己花了多年学习的技术如果不流行了,可能在就业市场上自己就贬值了。对应用开发工程师来说,ReactJS是个新技术,如果用ReactJS做过项目,在简历上可是个加分项呢。

不过,我觉得应用开发工程师不必太在意一时技术得失,只要是有新意的技术,都可以学。我10年前学习C++里的Boost模板元编程之类的技术,虽然没在项目中用上,但是我对类型系统的理解就更加深刻了,对我后来开发 Binding.scala 等几个框架都大有益处。

实际上 Binding.scala 的 API 要比 ReactJS、Vue.js 简单五到十倍。oss.sonatype.org/service/local/repositories/rel...
所以,我觉得你可以学一下 Binding.scala 再评论 Binding.scala 好不好学。

不过怎么样,谢谢你推荐 Binding.scala 。

Re: 水水水 by Yang Bo

既然你坚持数着代码行数来比优劣,那么React永远都不可能赢。
不过要是用Vue.js的话,可能会比你的代码更少,不知道你怎么看?


您错了。Vue.js 的 TodoMVC 例子中的 JavaScript 代码行数比 Binding.scala 的 Scala 代码长。
github.com/tastejs/todomvc/tree/master/examples...
github.com/ThoughtWorksInc/todo/blob/master/js/...

当然这样比较,对 Binding.scala 不太公平。因为 Vue.js 除了需要编写 JavaScript 以外,还需要额外编写 HTML 模板。而 Binding.scala 的 Scala 文件中有一半左右的代码都是 HTML 模板。

不过没关系,虽然对 Binding.scala 不公平,但 Binding.scala 还是能赢。

Re: 值得支持的项目 by 夏 鹏

感谢你能和我探讨这些。我基本算是一个做全栈开发的,这些年基本是项目指哪儿我就打哪个。这些年除了前端的Javascript、PHP,微软系的C#、WPF、WCF、ASP.NET MVC、.NET Core,移动应用的java、swift,Web服务器的node、nginx,sql数据库sql server、mysql,缓存redis,nosql的mongodb、azure的nosql存储等等。这些都是我一下子能够想起来的,可能没想起来的还有很多。因为都是项目需要什么,我就做什么。我感觉除了做项目,我没有业余时间,没有休息,都是不断地学习再学习。

可是几年过去,我发觉我很凌乱。因为我觉得我做了这么多事情,居然写不出一本书,不是说我非要写书,而是我感觉我自己居然找不到一个点能达到出书的水平。我很惆怅,因为我感觉我被技术玩儿了,而不是我在玩儿技术。于是我痛定思痛,决定缩小范围,其他一切都咔掉,然后再这个范围内做出我自己满意的成绩来。

当然我不是说其他技术我不接触了,而是不想像无头苍蝇一样乱撞了,为自己理一个清晰的主线来走比较好。

我希望你的Binding.scala,能够有朝一日能够和React、Angular相提并论,我也希望自己能够尽快参与到你这个开源项目中来,能够做出一个好东西,对于参与者来说都是一份了不起的成就感。Binding.scala这个github的项目我已经保存了,如果我遇到做scala,并且喜欢参与开源项目的同学,我会尽力向他们推荐的。

Re: 值得支持的项目 by Yang Bo

感谢你能和我探讨这些。我基本算是一个做全栈开发的,这些年基本是项目指哪儿我就打哪个。这些年除了前端的Javascript、PHP,微软系的C#、WPF、WCF、ASP.NET MVC、.NET Core,移动应用的java、swift,Web服务器的node、nginx,sql数据库sql server、mysql,缓存redis,nosql的mongodb、azure的nosql存储等等。这些都是我一下子能够想起来的,可能没想起来的还有很多。因为都是项目需要什么,我就做什么。我感觉除了做项目,我没有业余时间,没有休息,都是不断地学习再学习。

可是几年过去,我发觉我很凌乱。因为我觉得我做了这么多事情,居然写不出一本书,不是说我非要写书,而是我感觉我自己居然找不到一个点能达到出书的水平。我很惆怅,因为我感觉我被技术玩儿了,而不是我在玩儿技术。于是我痛定思痛,决定缩小范围,其他一切都咔掉,然后再这个范围内做出我自己满意的成绩来。

当然我不是说其他技术我不接触了,而是不想像无头苍蝇一样乱撞了,为自己理一个清晰的主线来走比较好。

我希望你的Binding.scala,能够有朝一日能够和React、Angular相提并论,我也希望自己能够尽快参与到你这个开源项目中来,能够做出一个好东西,对于参与者来说都是一份了不起的成就感。Binding.scala这个github的项目我已经保存了,如果我遇到做scala,并且喜欢参与开源项目的同学,我会尽力向他们推荐的。

我觉得你对自己职业生涯的思考很清晰。加油吧!

Re: 水水水 by 张 同学

说实话,感觉您的优越感都透过电脑屏幕渗出来了。

Re: 水水水 by Yang Bo

我理解您可能有“你不就是写了个比ReactJS好的框架吗?有什么了不起?”这样的情绪。

不过我觉得作为专业技术人员,您如果觉得 ReactJS 就是世界上最好的框架,别人介绍的其他框架都只是“优越感”就视而不见,那么我觉得这样容易限制您的技术视野,对您的职业生涯可能不是特别好。

区别只在数据绑定而已 by chao wang

如果把react的代码使用stateless component的方式实现,并不会比binding.scala多那么多行代码。
而binding.scala的那些代码行数的优势实际上只是来自于
Vars 是支持数据绑定的列表容器
这句话而已。

但是React并没有提供数据绑定的东西,本身的定位只是View。也因此能出现react-native,react-desktop,react-canvas这样的东西。数据绑定的部分现在社区都有很多解决方案了,如redux和mobx等

而在我看来,binding.scala看起来只是提供了数据绑定的功能而已。

Tag Editor reactjs 15行版本 by chao wang

tags是一个immutablejs的set对象,所以现在你看除了数据绑定以外,还有什么差别?行数嘛?

const TagEditor = ({onChange, tags}) => (
<section>
<div>
{tags.map((tag, index) => (
<div key={index}>
{tag}
<button onClick={() => onChange(tags.delete(tag))}>x</button>
</div>
))}</div>
<div>
<input type="text" ref="input"/>
<button onClick={() => onChange(tags.add(this.refs.input.value))}>Add</button>
</div>
</section>
)

Re: Tag Editor reactjs 15行版本 by Yang Bo

你的洞察力不错!归根到底,ReactJS就是因为缺乏通用数据绑定能力,所以没办法简单复用组件。

《More than React》系列的下一篇文章就会比较ReactJS的虚拟DOM和Binding.scala的精确数据绑定机制。到时候你可以关注一下。

Re: 区别只在数据绑定而已 by Yang Bo

数据绑定的部分现在社区都有很多解决方案了,如redux和mobx等


数据绑定部分,的确JavaScript社区有很多解决方案。不过Redux可能不能算“通用”的数据绑定,对前端开发者如何使用,限制重重。实际用起来会比直接用ReactJS还要繁琐。

Reddit上也有人提到了MobX。我简单看了一下,MobX的API数量要比Binding.scala多十倍,但MobX几乎所有功能Binding.scala都可以用同一个API(即bind)解决。我不明白为什么MobX需要这么多API。

如果你很熟悉MobX的话,我觉得你可以写一篇评测文章比较一下MobX和Binding.scala,我也好学习一下MobX的作者是怎么想的。

Re: 水水水 by 吴 浩

欢迎您提供一些 Flux 或者 Redux 的例子,和 Binding.scala 对比。



github.com/gitwuhao/antd-plus

这个项目是用redux写的,还实现了拖拽,不知道算不算复杂,反正用react写成之后感觉还不错。

Re: 值得支持的项目 by Lee Jerin

因为我感觉我被技术玩儿了,而不是我在玩儿技术。于是我痛定思痛,决定缩小范围,其他一切都咔掉,然后再这个范围内做出我自己满意的成绩来。


支持!加油 ↖(^ω^)↗

支持!加兴趣十足 by zheng jemmy

看您第一篇的时候,心理还有点不爽,本人是十足的ReactJs热爱者,但是最近开发了一整个较为复杂的应用,在使用react的时候的确遇到很多您说的语法噪音,虽然我还是会继续使用React,毕竟技术转型还是要成本的(对公司而言)哈哈,不过我对您的这个框架,确切的说,您的框架让我对scala很感兴趣,而且对您的技术水平和对技术的热爱感到由衷的佩服!

这个例子举的不好 by lao kuan

我就觉得前端框架就应该“轻”一点,就实现View的功能好了,在实际的项目中,持久化数据应该是在后端实现的。
你的例子中Tags这个数据都是“写死在前端界面中的”,但是在实际项目中,这些数据大部分都应该是存放在后台数据库中的吧?
这样一来tags: [ "initial-tag-1", "initial-tag-2" ]这个变量不太可能仅仅在前端框架中持久化保存吧?所以,我认为这个数据肯定就是这个组件的一个内部数据,当编辑完成之后可能会通过Ajax之类的传到后台。因此,我觉得实现这个组件,也就需要props传入就够了,组件内部仅仅需要保存变化之后的变量。只是这个props引入的变量需要用一个“全局的json的数据”完成和后台数据的交互。如果页面其他组件显示针对这个tags的变化,则也需要引用这个“全局的json的数据”。如果是在这样的背景下,React肯定是有优势的,因为React同时支持原生态的js语言,数据交换可以封装在json等格式中传递。
我对Binding.scala不太了解,但是第一感觉是语法糖不如js清楚,我觉得如果考虑和后台的数据交互,实现起来也不一定很简单。
我觉得你这个例子完全就是针对React的“数据单向”的缺点,本身React的组件就是“单向数据设计”,出现大量的数据嵌套数据传递,我觉得不是React的问题,而是整体设计上有问题,或者就是项目不适合用React。因此,你的题目叫“组件对复用性有害?”有点夸张的感觉。
但是我在用React的时候,确实没有出现过三层组件以上的数据传递。

Re: 这个例子举的不好 by Yang Bo

Binding.scala也是单向数据设计,处理大量数据嵌套完全没问题。
Binding.scala的用户反馈说: I really like Binding.scala for making small reusable, isolated components.
本文并不是针对“单向数据设计”,而是针对ReactJS繁琐、冗余的单向数据设计。


至于您说的后台数据交换,请您关注一下More than React (五)。InfoQ的编辑说近期就会发表出来。
Binding.scala的远程数据绑定功能,相比原生态的异步编程的巨大优势,可能会让您大吃一惊。

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

26 讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT