zoukankan      html  css  js  c++  java
  • React设计思想

    熟悉一个新技术的关键是熟悉他的特色和理念

    React框架本身和我们常用的JavaScript MVC框架,如:AngularJS,Backbone,Ember等,没有直接的可比性。在React的官方博客中明确阐述了React不是一个MVC框架,而是一个用于构建组件化UI的库,是一个前端界面开发工具。所以顶多算是MVC中的V(view)。React并没有重复造轮子,而是有很多颠覆性的创新,具体的特性如下:

    编写简单直观的代码

    在年初的React开发者大会上,React的项目经理Tom Occhino讲述了React的最大的价值,React最大的价值不是高性能的虚拟DOM、封装的事件机制、服务器端渲染,而是声明式的直观的编码方式。React号称能让新人第一天开始使用就能开发新功能。简单的编码方式会让新手能很快地上手,同时也降低了代码维护的成本。这一特性决定了React能快速引起开发者的兴趣并广泛传播的基础。以下是React基于这一理念的具体做法。

    简化可复用的组件

    React构建UI是使用组件化的方式,而不是常见的模板。组件并不是一个新概念,它是某个独立功能或者界面的封装,达到复用或者UI和业务松耦合的目的。

    组件化的设计理念也出现了很多年了,我们常用的ExtJS、YUI、jQueryUI、BootStrap等等都会提供大量的可复用的UI组件。比如在Bootstrap中使用对话框组件:

    // 初始化
    $('#myModal').modal({
        keyboard: false
    });
    
    // 显示
    $('#myModal').modal('show');
    
    // 关闭事件
    $('#myModal').on('hidden.bs.modal', function (e) {
      // do something...
    });

    可以看到我们常用的这些组件提供了大量的接口和配置,让开发者选择合适的使用场景。这些组件的设计复杂,使用也较繁琐,新人上手有一定的门槛。W3C也在加紧制定Web Components(即组件)的标准,试图制定一个统一的简单实用的标准化的组件概念。我们看看React是如何设计组件模型的以及其和Web Component的区别。

    React框架里面使用了简化的组件模型,但更彻底地使用了组件化的概念。React将整个UI上的每一个功能模块定义成组件,然后将小的组件通过组合或者嵌套的方式构成更大的组件。这种做法已经在instagram网站上普遍实施,大家可以看看instagram的前端源代码。 如下通过一个简单的例子来阐述React中模块化的概念。这个例子来自于React的官方网站教程,是完成一个简单的评论框。这个评论框主要包含两个部分,评论列表和评论表单。显示效果如下:

    按照React模块组合的设计,把评论框组件commentBox分为两个子组件模块:commentList和commentForm,代码如下:

    <div className="commentBox">
      <h1>Comments</h1>
      <CommentList data={this.state.data} />
      <CommentForm onCommentSubmit={this.handleCommentSubmit} />
    </div>

    commentList和commentForm组件对应的代码如下:

    <div className="commentList">
      {commentNodes}
    </div>
    
    
    <form className="commentForm" onSubmit={this.handleSubmit}>
      <input type="text" placeholder="Your name" ref="author" />
      <input type="text" placeholder="Say something..." ref="text" />
      <input type="submit" value="Post" />
    </form>

    从代码中可以看到CommentList组件又可以划分为comment组件的列表。comment组件代码如下:

    <div className="comment">
      <h2 className="commentAuthor">
        {this.props.author}
      </h2>
      <span dangerouslySetInnerHTML= />
    </div>

    可以看出,为了完成评论框功能,使用React定义了四个不同的组件:commentBox、commentList、commentForm、comment。commentBox是由commentList和commentForm组合而来,commentList是由comment组合而来。这个例子充分体现了React组件化的理念,每个组件的UI和逻辑都定义到了内部,暴露少量的API和外部交互,组件之间组合形成更复杂的组件。总结一下,React的组件具有如下的特性:

    • 可组合:简单组件可以组合为复杂的组件

    • 可重用:每个组件都是独立的,可以被多个组件使用

    • 可维护:和组件相关的逻辑和UI都封装在了组件的内部,方便维护

    • 可测试:因为组件的独立性,测试组件就变得方便很多。

    React使用了组件化的设计,所以开发者自然而然和原生的Web Components相提并论,StackExchange上有一篇精彩的讨论,解释了React的组件和原生组件的对比。文章从语言层面、样式的封装、数据绑定、DOM操作方式等这几个方面展开讨论,结论是说两者没有优劣之分,只是编码习惯问题。Web Components规范毕竟还在制定过程中,应该可以从React的组件设计方式上借鉴一些理念。在后续的文章中,会深入探讨React中组件的设计原理及使用。

    虚拟DOM

    在JavaScript中DOM操作是独立成为一个分支的。各浏览器在实现DOM操作库也是大同小异,都是在单独的模块中实现了DOM操作,由于各种技术上的原因,DOM操作的性能损耗相对于其他操作是很大的。在前端开发中都是需要特别尽量保持较小的DOM操作次数来提高性能。

    React作为一个UI框架,不可避免要有界面上元素的交互。为了提高性能,React在操作页面交互时引入了虚拟DOM的概念。虚拟DOM是在React中用JavaScript重新实现的一个DOM模型,和原生的DOM并没有多少关系,只是借鉴了原生DOM的一些概念。虚拟DOM并没有完全实现DOM,只是保留了元素直接的层级关系和少量必要的属性。因为减少了不必要的复杂性,实践校验的结果是虚拟DOM的性能比原生DOM高很多。来看看普通DOM和虚拟DOM在代码上的差别。

    如下是使用原生DOM生成的元素:

    var a = document.createElement('a')
    a.setAttribute('class', 'link')
    a.setAttribute('href', 'https://github.com/facebook/react')
    a.appendChild(document.createTextNode('React'))

    那么使用虚拟DOM则代码为如下:

    var a = React.createElement('a', {
        className: 'link',
        href: 'https://github.com/facebook/react'
    }, 'React')

    可以看到React中使用了自己实现的createElement方法来生成元素DOM结构。

    基于React开发中构建的DOM都是通过虚拟DOM进行的。在React的实际的使用中,需要根据不同的数据展现不同的UI,当数据变化时,React会重新构建整个DOM树,然后将当前的DOM树和之前的比较,得到DOM树的区别,然后仅仅把变化的部分反映到实际的浏览器UI更新上。React会在同一个事件循环内合并DOM的变化,只是会对比开始和结束的DOM变化,忽略中间过程的DOM变化。尽管每次数据变化都是重新构建DOM树,但虚拟DOM的操作性能极高。这样使用React时,开发者不在需要关心数据变化时页面上DOM元素的更新,而只是关心各个数据状态下页面实际展现的效果。此外,因为React使用了由JavaScript实现的虚拟DOM,意味着可以在服务器端完成HTML结构的构建。

    JSX

    JSX是React的重要组成部分,他使用类似XML标记的方式来声明界面及关系,所以他只是一个文档规范。如下是一个在React里面使用JSX的例子:

    var HelloMessage = React.createClass({
      render: function() {
        return <div>Hello {this.props.name}</div>;
      }
    });
    
    React.render(<HelloMessage name="John" />, mountNode);

    可以看到如上使用了JSX的代码,像是HTML和JavaScript代码的混合体。很多人很不习惯这样的编码方式,认为这和我们一直倡导的表现和逻辑分离的思想相违背,是一种倒退。那么React这样的设计用意是啥呢?

    React一个主要的设计理念是编写简单容易理解的代码。HTML模板的作用是让表现和逻辑分离,但是很多情况下模板还是严重依赖于业务逻辑,两者没有办法做到完全的松耦合。稍微复杂一点的例子,比如AngularJS使用了一套独特的机制来让UI和逻辑交互,示例代码如下。

    <ul class="unstyled">
      <li ng-repeat="todo in todoList.todos">
        <input type="checkbox" ng-model="todo.done">
        <span class="done-"></span>
      </li>
    </ul>

    使用AngularJS的确从代码角度做到表现和逻辑分离,但是在HTML里面混入了大量的属性标记,这些标记但从语义上很难理解,新手比如要整个熟悉Angular中每个类似ng-*对应的用法及意义才能理解整个逻辑,所以有一定的入门门槛。如上例子使用JSX方式编写如下:

    render: function () {
      var lis = this.todoList.todos.map(function (todo) {
        return  (
          <li>
            <input type="checkbox" checked={todo.done}>
            <span className="done-{todo.done}">{todo.text}</span>
          </li>);
      });
      return (
        <ul class="unstyled">
          {lis}
        </ul>
      );
    }

    可以看到,JSX中除了使用HTML标记之外,并没有复杂的标记。这种自然而直观的方式直接降低了React的学习门槛并且让代码更容易理解。

    JSX只是简化了React的使用难度,但并不是必须的。在React中也可以不使用JSX,而是使用原生JavaScript的方式编写代码。在实际使用过程中也是把JSX转换成了JavaScript代码来运行的。React官方网站上提供了一个在线转换JSX到原生JavaScript代码的工具,通过这个工具也可以体会JSX使用上的优势及其内在原理。

    Flux

    Flux是另外一个独立于React的架构。之所以说Flux是一个架构而不是框架或者类库,是因为Flux仅仅用于配合React框架来处理组件和数据之间的交互。简单来说Flux就是用于管理数据流。和其他MVC框架倡导的双向数据绑定不同,Flux使用了单向数据绑定的机制,即数据模型到视图的流动。如下两个图展示MVC和Flux之间的差异:

    Flux中主要使用了三个概念:Dispatcher、Action和Store。这三个概念区别于MVC的model、view和controller概念,因为MVC中更多的是数据双向绑定。

    Actions是用于传递数据给Dispatcher的操作集合。Action可能来自于用户界面的操作,也可能是服务器端的数据更新。

    Dispatcher是一个全局的分发器,接受Action,并传递给注册的回调函数。

    Stores包含了应用的状态及注册到Dispatcher的回调函数,这些函数用于处理业务逻辑。

    和React Views最密切的是Store,React view从Store取得state和其他数据,并更新界面。

    总结

    从以上的React相关设计可以看出,React是以降低前端开发的复杂度为原则的。使用React编写的代码也易于理解,所以适合大规模多人开发,能提高项目的开发效率和质量。

  • 相关阅读:
    不常用的cmd命令
    js获取宽度
    Marshaling Data with Platform Invoke 概览
    Calling a DLL Function 之三 How to: Implement Callback Functions
    Marshaling Data with Platform Invoke 之四 Marshaling Arrays of Types
    Marshaling Data with Platform Invoke 之一 Platform Invoke Data Types
    Marshaling Data with Platform Invoke 之三 Marshaling Classes, Structures, and Unions(用时查阅)
    Calling a DLL Function 之二 Callback Functions
    WCF 引论
    Marshaling Data with Platform Invoke 之二 Marshaling Strings (用时查阅)
  • 原文地址:https://www.cnblogs.com/gankehuang/p/8471477.html
Copyright © 2011-2022 走看看