ReactJS :我就是想把代码和HTML混在一起!

开发 开发工具
当我走进这个著名的咖啡馆,这里已经有很多人了,我环顾四周,看到远处的JSP同学和ASP同学正聊得火热,他俩,还有今天没看见的Velocity同学每次都会占据最里边的座位,似乎故意要逃避大家。

 当我走进这个著名的咖啡馆,这里已经有很多人了,我环顾四周,看到远处的JSP同学和ASP同学正聊得火热,他俩,还有今天没看见的Velocity同学每次都会占据最里边的座位,似乎故意要逃避大家。

从他们的表情看,我就能猜出来这两个家伙又在抱怨人心不古,世风日下,没有程序员使用他们了。

旁边是jQuery和ExtJS, 他俩在低声交谈,时不时朝JSP和ASP方向看两眼, 我估计jQuery又在宣传他那DOM操作大法了。

幸好,还有一个靠窗的空桌,有两个座位, 我走过去坐下,要了一杯咖啡,拿起一本杂志,边喝边看。 

[[238363]]

代码中混杂HTML

这时候又进来一个年轻人,看到我这一桌还有空位,不客气地坐下, 掏出一张纸,爬在桌子上刷刷刷地写代码。

我偷偷看了一眼,不由得大吃一惊: 怎么能在代码中写HTML呢?

  1. function Welcome(props) {     
  2.     return <h1>Hello, {props.name}</h1>; 

这时候服务员正好走过来送咖啡, 也注意到了这段代码, 大叫道:“我赛,这都什么年代了,还在代码里写HTML !”

这一下便炸了锅,ASP, JSP, jQuery, ExtJS等纷纷围过来看个究竟。

在代码中写HTML,我记得这是上个世纪90年代的事情,那时候连ASP,JSP都没有,只好用C语言写CGI代码,HTML就混杂在C代码中,类似这样:

  1. void main(){ 
  2.     char content[MAXLINE]; 
  3.     sprintf(content,"<html>"); 
  4.     sprintf(content,"<head>"); 
  5.     sprintf(content,"<title>Homepage</title>"); 
  6.     sprintf(content,"</head>");  
  7.     ......其他内容略......  
  8.     printf("Content-length : %d \r\n",(int)strlen(content)); 
  9.     printf("Content-type:text/html \r\n\r\n"); 
  10.     printf("%s",content); 
  11.     fflush(stdout); 
  12.     exit(0); 

这种模式给修改界面和业务逻辑带来了巨大的麻烦,等到ASP, JSP这样的“模板”语言出现以后,变成了在HTML中写代码: 

UI设计师先把HTML页面整体设计好,交给程序员再用<%..%>在其中填入动态的部分, 这种方式可以让设计师和程序员更好地合作。

  1. <%@ Language="VBScript" %> 
  2. <html> 
  3. <head><title>我的主页</title></head> 
  4. <body> 
  5. <% For i=3 to 5 %> 
  6. <font size=<%=i%> > 
  7.     你好,欢迎来到我的主页。 
  8. </font> <br /> 
  9. <% Next %> 
  10. </body> 
  11. </html> 

现在又有人想在代码中写HTML,简直是疯了!

模板 vs 组件

看到这么多人围过来, 小伙子涨红了脸:“我这不是HTML,我这个是JSX,是JavaScript的一个语法扩展,你们仔细看看,其实和ASP的模板也很像的。”

<h1>Hello, {props.name}</h1>

“那你为什么不直接用模板,为什么要把HTML放到JavaScript当中?这是我们早就抛弃的反模式!”  ASP问道。

“对啊,为什么不用模板? ”  周围的人也随声附和。

“因为我觉得模板难于复用!” 小伙子突然大声说道。

说起复用,这一点我的体会太深了,在开发中,我通常把描述界面结构的HTML,描述展示的CSS, 和操作DOM的JavaScript放在不同的文件当中,在运行时把他们结合起来, 但是这种分离只是技术层面分开管理而已,在逻辑上并没有实现高耦合的组件,也就无法复用。

“我想了一个新的办法,” 小伙子继续说道,“组件化,我们可以创建一个个的组件,然后让这些组件组合起来形成一个完整的Web界面。 就像我刚写的组件Welcome,可以复用的,可以用在Web页面的任何地方。”

“组件? 这小子有点想法。” ASP说道,“我表哥Visual Basic 就有很多组件,奥,好像大家叫他控件,在开发一个应用的时候,只需要把控件拖拽到表单界面上,设置属性,编写对事件的处理代码就可以了,非常简单快速。”

“你怎么没给我说过?” JSP表示不满, 他和ASP在90年代打得你死我活,现在抛弃了门户之见,成了好基友。

小伙子向ASP投去感激的目光,找到支持支持者了。

没想到ASP马上泼了一盆冷水:“不过控件是在桌面应用使用的,在Web开发中我们不这么干,它和桌面应用差别太大,实现不了。”

小伙子马上反驳:“怎么实现不了,一个组件不就是一个可以复用的单元吗? 在Web页面上, 这个组件要像桌面应用那样,负责自己的展示和行为,有属性可以设置,有方法可以调用,对外可以响应事件(Event), 对内可以维护组件状态。”

我说道:“你说说你那个Welcome组件具体怎么复用?”

小伙子说: “很简单,在JSX中,那个Welcome组件就像普通的HTML标签一样,直接就可以使用了!”

  1. function App(props){ 
  2.   return
  3.     <div>      
  4.       <Welcome name="码农翻身" /> 
  5.       <Welcome name="张大胖" />       
  6.     </div> 
  7.   ); 

确实是不错,这些自定义的标签(组件),可以一层层地组合起来,构建成一个大的页面。

有状态的组件

还是jQuery经验老道,他眯着眼看了半天,开始发难:“你号称是组件,但组件都是有内部状态的,而你这代码就是一个函数而已,一个输入,一个输出,根本不是组件!”

小伙子说:“你说得没错,那个组件是个无状态的组件,只有输入和输出,我给你看个有状态的组件。”

  1. class Counter extends React.Component{ 
  2.    constructor(props){ 
  3.      super(props); 
  4.      this.state = {count : 0}; 
  5.    } 
  6.    handleClick(){ 
  7.      this.setState({count: this.state.count + 1}); 
  8.    } 
  9.    render(){ 
  10.      return ( 
  11.        <div> 
  12.          <button onClick={(e) => this.handleClick(e)}>Click!</button> 
  13.          <h3> 
  14.            Click Count : {this.state.count
  15.          </h3> 
  16.        </div> 
  17.      ); 
  18.    } 
  19.  } 

这个组件一下子就复杂多了,似乎是一个继承了Component的类,有构造器,有函数,还有个返回HTML的render方法。

小伙子说:“看到没有,这是一个用来计数的小组件, 数值被保存起来了,就是那个 this.state.count ,初始值为0, 每次点击就会调用this.setState函数,把count 加一。”

小伙子说着在浏览器中给我们展示了一下效果,果然,每次点击,Count数都会变化。

我们看了以后都有一个感觉,这确实是一个组件,你看它内部有展示的逻辑,有状态,有操作,自己的活儿自己干。

“state ? 你不是有props吗? 还用state ? ” ExtJS 看到jQuery沉默了,马上为朋友两肋插刀。

小伙子说道:“是这样的,我用props 来保存从上层组件(父组件)传递过来的数据,用state来保存本组件的内部数据。”

jQuery道:“父组件可以用props给子组件传递数据,那子组件如果想把数据告诉父组件,该怎么处理?”

小伙子向jQuery投去佩服的目光, 回答道:“这个问题我想过了,父组件可以用props传递一个'钩子'函数给子组件,在必要的时候,子组件就调用这个函数,把数据告知父组件。”

UI = render(data)

jQuery不甘心,想了一会儿,又抛出一个重磅炸弹:“怪哉怪哉,从你这个Counter组件中,怎么看不到对DOM的操作? 如果没有DOM操作,你怎么实现点击了Click! 按钮以后,下面的数目发生变化的? ”

jQuery是操作DOM的高手,什么链式调用了,选择器了被他玩得贼溜,现在看到Counter组件中连一行DOM操作的代码都没有,颠覆了自己的人生观,肯定要弄个究竟。

“我估计大家都用JavaScript操作过DOM,说实话,很简单,很直观,可是当项目变得复杂以后, 当页面上的事件处理多了以后, JavaScript的代码会和DOM紧密地纠缠在一起,就不好维护了。”  小伙子说道。

大家都纷纷点头。

“所以呢, 所以我就想办法把他屏蔽了,在我这里,不用操作DOM,只要你调用setState方法,我发现数据发生了变化,我就会渲染整个页面。所以对程序员来讲,在概念上非常简单,只需要setState,剩下的操作都交给我。 用个公式来表达就是 UI = render(data) 。  ”

“嘶.....”    听到这个“渲染整个页面”,大家伙都倒吸了一口凉气。如果一个页面有很多数据,现在只改变了一个小小的count的数值 ,难道还要把其他的也全部渲染一遍?

看到大家疑惑的表情,小伙子笑了笑,解释道:“全部渲染是从概念上来说的,在实现层面,还是局部更新。为了实现这一点,我特意实现了一个虚拟的DOM。”

“每次数据发生了变化,我会比较两个虚拟DOM的区别,找到那些数据真正发生改变的地方,然后操作真正的DOM, 这样以来,其实真正的更新还是局部的。”

看到了虚拟DOM, 大家都明白这小伙子绝对不是一般人了!。

但是看到那混杂着代码和HTML的,试图改变Web开发方式的“组件”,都觉得不可思议,难以接受,摇着头,慢慢地散开了。

ASP一边走一边给JSP说:“这玩意儿,太颠覆了,根本不会有人用。”

JSP同意:“是啊,我们还是玩模板去吧。”

人走得差不多了,我问小伙子:“你叫什么名字? ”

“ReactJS。”

“有没有兴趣到我们公司工作? ” 我递上了我的名片,上面印着我们公司的Logo : Facebook。

【本文为51CTO专栏作者“刘欣”的原创稿件,转载请通过作者微信公众号coderising获取授权】

戳这里,看该作者更多好文

责任编辑:武晓燕 来源: 51CTO专栏
相关推荐

2013-08-06 09:49:01

2018-02-01 21:18:40

戴尔

2011-01-20 11:42:49

同事

2015-10-20 16:48:06

AnsibleDocker可扩展设计

2016-09-02 16:49:54

APPVR

2009-11-06 08:57:31

WCF开发

2016-08-12 09:49:06

Intel

2009-07-22 09:29:44

ScalaSpiral程序

2015-03-05 10:27:56

苹果IBM

2021-03-15 10:26:29

边缘计算云计算混合云

2022-05-06 14:19:02

边缘计算物联网5G

2019-01-03 13:58:53

人工智能大数据数据分析

2020-09-16 11:20:40

PythonBashLinux

2017-11-15 08:26:52

IntelAMD技术

2015-11-16 17:13:05

巴黎恐怖袭击互联网公司

2015-11-12 10:23:35

5G物联网

2015-02-09 19:49:19

畅捷通

2015-04-22 17:22:05

eBay京东

2020-11-30 10:30:01

神经网络感知机中间层

2023-03-30 16:23:09

人工智能AI
点赞
收藏

51CTO技术栈公众号