转载

我是怎么从顾虑到热爱ReactJS的(与AngularJS经典MVC数据绑定的对比)

如果你问我两个月前怎么看 React,我可能会说:

我的模板在哪?在我的JavaScript里写这么多HTML干什么?JSX看起来很怪!赶快把它从我的项目里面去掉!

这是因为我还不了解它。现在我保证,React决定是正常的路径,请听我尾尾道来。

经典的MVC

在一个交互式应用程序中状态的管理是一切罪恶的根源。“传统”的方式是采用MVC架构,或者是一些变种。

MVC提出你的模型(Model)是检验真理的唯一来源 - 所有的状态都在那里。视图(View)源自模型,并且必须跟模型保持同步。当模型转变时,视图也要同步改变

最后,用户通过控制器(Controller)控制交互,由它更新模型。到目前为止,这工作地很好。

我是怎么从顾虑到热爱ReactJS的(与AngularJS经典MVC数据绑定的对比)

当Model改变时重绘View

这看起来很简单。首先,我们需要来详细我们的View - 它是一个对DOM的映射。然后,每当用户更新模型时重绘整个DOM,对吧?不幸的是,事情不是这么简单,原因有二:

1. DOM 实现上是有状态的, 像input文本的内容。如果你重绘整个DOM, 这部分内容就会丢失。

2. DOM 操作 (像移除插入的结点) 真的非常慢. 持续不断地重绘会导致严重的性能问题。

所以,我们怎样同步Model和View来避免上面的问题?

数据绑定 Data binding

在过去3年,框架级别的通用解决方案是采用数据绑定。

数据绑定是让你的模型和视图,拥有自动同步的能力。通常情况下,是将JavaScript对象和DOM进行同步。

它通过你的数据声明的组件之间的依赖关系来实现。状态的变化会在整个应用程序中传播并通知所有依赖的对象,然后自动更新。

让我们来看看它是如何工作的和一些著名的框架。

Knockout

Knockout主张MVVM模式,并帮助您实现“View”部分:

// View (一个模板)

<p>First name: <input data-bind="value: firstName" /></p>  

<p>Last name: <input data-bind="value: lastName" /></p>  

<h2>Hello, <span data-bind="text: fullName"> </span>!</h2>

// ViewModel (diplay data... and logic?)

var ViewModel = function(first, last) {  

this.firstName = ko.observable(first);

this.lastName = ko.observable(last);

this.fullName = ko.pureComputed(function() {

// Knockout 会自动侦听依赖。它知道fullName会依赖firstName和lastName.

return this.firstName() + " " + this.lastName();

}, this);

};

然后,万事大吉了。改变任一输入的值将触发DOM的变化。你从来不用写数据与视图关连的逻辑代码。效果不错,是吧?

为什么模型是真理的唯一来源?这个ViewModel应该从哪里获取状态?它是如何知道Model的变化的?这是很有趣的问题。

Angular

Angular介绍了如果在Model和View之间同步数据。下图来自其文档:

我是怎么从顾虑到热爱ReactJS的(与AngularJS经典MVC数据绑定的对比)

但是......View应该与Model直接通信吗?难道他们是紧耦合的?

无论如何,让我们来看看Hello World示例:

// View (一个模板) 

<div ng-controller="HelloController as hello">  

<label>Name:</label>

<input type="text" ng-model="hello.firstName">

<input type="text" ng-model="hello.lastName">

<h1>Hello {{hello.fullName()}}!</h1>

</div>

// Controller 

angular.module('helloApp', [])  

.controller('HelloController', function() {

var hello = this;

hello.fullName = function() {

return hello.firstName + hello.lastName;

};

});

通过这个例子,Controller看起拥有自己的状态,而且表现的像个Model或者一个ViewModel?假设Model是其它的什么东西,它是如何保持跟Controller的同步的呢?

data binding的问题

数据绑定在小的例子里工作地很好。然而,当你的app不断地迭代时。你可能会碰到下面的问题。

声明依赖会快速地引入循环

最常见的问题是在应对状态变化时所产生的副作用。从Flux的这篇报道可以很清楚地了解依赖地狱的蠕变:

我是怎么从顾虑到热爱ReactJS的(与AngularJS经典MVC数据绑定的对比)

在这种情况下,你能预测当一个Model发生变化时会发生什么吗?推理是非常非常困难的,因为它的执行次序可能是非常随意的。

模板和显示逻辑被人为地割裂

视图的作用是什么?呈现的数据显示给用户。ViewModel是干什么的?呈现的数据显示给用户。有什么区别?没有!

模板分离技术,我不关注〜 皮特·亨特

最后,一 个视图组件应该能够操纵它的数据,并能以所希望的格式呈现它。但是,所有的模板语言本质上是残缺的:他们永远不能达到同样的表现力和效能的代码。

非常简单,{{# each}}, ng-repeat 和 databind="foreach" 都仅能替代天然的和琐碎JavaScript中的一个for循环。不能再进一步。因为,没有filter或map提供给你。

Data binding 是围绕重新渲染的Hack手法

当状态变化时,人们都希望重新渲染整个应用。通过这种方式,我们可以阻止一个万恶问题:状态是随时间变化的。

了解Facebook的React框架

事实证明,他们做到了。React实现了一个虚拟DOM(virtual DOM)来解决上面的问题。

virtual DOM到底是什么?

我们来看一看React的例子

var Hello = React.createClass({  

render: function() {

return <div>Hello {this.props.name}</div>;

}

});

React.render(<Hello name="World" />, document.getElementById('container')); 

这就是一个React组件的所有代码。你只需要有一个渲染方法。复杂吗?

OK,<DIV>是什么?这不是JavaScript的写法!确实JS里肯定没有这个东西。

你的新朋友: JSX

这个码被实际是用JSX写的,一个Javascript的超集,其使用括号语法定义组件。上面的代码,当编译成JavaScript时,将变成:

var Hello = React.createClass({displayName: "Hello",  

render: function() {

return React.createElement("div", null, "Hello ", this.props.name);

}

});

React.render(React.createElement(Hello, {name: "World"}), document.getElementById('container'));  

你有没有注意到调用的createElement?这些对象组件的Virtual DOM实现。

很简单:首先React在内存中组装整个应用程序的结构,使用这些对象。然后,它把这个结构转化为实际的DOM节点,将它们插入您浏览器的DOM中。

OK,但是为什么我们的HTML要变化那些奇怪的createElement函数呢?

Virtual DOM 非常快

正如我们已经讨论的,操纵DOM贵的离谱,所以这个操作做得越少越好。

React的Virtual DOM,使得这个操作变得很快。通过这种方式,React能够比较两种DOM树的差异,然后计算出能使DOM新化所需的最小变化。这意味着两件事情:

如果输入文本重新呈现和阵营期望它有该内容,它不会触及输入。没有更多的亏损状态!

如果React重新渲染Text的内容。它不会动input。不会有状态丢失。

比较的Virtual DOM的性能还可以,当它会在准备改变DOM前进行充分的比较,它只会执行尽可能少的操作。因此渲染是很快的!

React印射状态到DOM中

Virtual DOM在渲染进行进行比较的是React魔法的一部分。并且它能从根本上使我们能够有一个更简单的框架。多么简单?

这是一个React组件应该有的功能,它能将应用程序的状态映射到DOM中。你能发挥JavaScript的全部能力来描述你的UI - 循环,函数,Scope,组件,模块 - 它不是一个残缺的模板语言。

var CommentList = React.createClass({  

render: function() {

var commentNodes = this.props.data.map(function (comment) {

return (

<Comment author={comment.author}>

{comment.text}

</Comment>

);

});

return (

<div className="commentList">

{commentNodes}

</div>

);

}

});

var CommentBox = React.createClass({  

render: function() {

return (

<div className="commentBox">

<h1>Comments</h1>

<CommentList data={this.props.data} />

</div>

);

}

});

React.render(  

<CommentBox data={data} />,

document.getElementById('content')

);

开始用React

第一次用React可能有点另人生畏。它提出了一个非常大的风格转变,这其实不是很舒服。然而,当你开始用时,你会发现优势明显。

快乐编码!

React 文档: https://facebook.github.io/react/docs/getting-started.html

原文地址:点此

正文到此结束
Loading...