秒懂ReactJS | TW洞见

今日洞见

文章作者/配图来自ThoughtWorks:贾朝阳。

本文所有内容,包括文字、图片和音视频资料,版权均属ThoughtWorks公司所有,任何媒体、网站或个人未经本网协议授权不得转载、链接、转贴或以其他方式复制发布/发表。已经本网协议授权的媒体、网站,在使用时必须注明"内容来源:ThoughtWorks洞见",并指定原文链接,违者本网将依法追究责任。

这篇文章是为ReactJs小白准备的,希望他们快速抓住ReactJs的要点并能在实践中随机应变。

两句话版本

  • ReactJs把视图更新简化为一个render函数
  • render函数接收两个参数,分别是配置项和状态

长版本

ReactJs是一个专注于View的Web前端框架。Web前端的View就是浏览器中的Dom元素,改变View的唯一途径就是修改浏览器中的Dom元素,因此ReactJs的核心任务就是如何修改Dom元素,作为一个成功的框架,ReactJs使修改Dom元素变得高效而又简单。

ReactJs把修改Dom的操作简化成一个函数renderInto(parentDom, props, states)=>htmlString,这个函数的意图就是根据props,states计算出视图对应的html字符串并添加为parentDom的子节点。props和states就是普通的javascript对象,这个函数的核心逻辑就是计算html元素的机构及元素属性然后拼接成字符串返回。作为框架,ReactJs用JSX形式的DSL解决了拼接html的任务并接管了更新到parentDom的职责。看一个例子,理解这个函数并理解ReactJs怎么使用这个函数你就可以一个人开始ReactJs之旅了。

var props = {name: 'myname'};  
var states = {amount: 1000};  


function render(props, states) {  
  var title = ’Hello, ' + props.name;  
  var description = 'You have ' + states.amount + ' score now.';  


  return (  
    <div className="score-board">  
       <h1>{title}</h1>  
       <p>{description}</p>  
    </div>  
  );  
}

函数第一行根据props计算title,第二行根据states计算description,最后以JSX形式返回拼接好的html字符串。

如果你用过AngularJs,EmberJs等类似的前端框架,你可能会觉得没什么了不起,不就是把模板和逻辑放到一起吗?是的,没错,但这不仅仅是组织形式上的改变,而是编程隐喻的转变—从复杂的MVC或MVVM模式到简单的render函数。还有一点不同是JSX最终编译成调用react-dom的javascript语句,而不是直接生成字符串。

render函数还只是ReactJs这座冰山的一角,”React”会在render函数的输入变化时再次调用这个函数。再看一个例子。

var props = {name: 'myname'};  
var states = {amount: 1000};  


function handleClickAdd() {  
  states = {amount: states.amount + 1};  
}  


function render(props, states) {  
  var title = ’Hello, ' + props.name;  
  var description = 'You have ' + states.amount + ' score now.';  


  return (  
    <div className="score-board">  
       <h1>{title}</h1>  
       <p>{description}</p>  
       <button onClick={handleClickAdd}>+1</button>  
    </div>  
  );  
}

这个例子增加了一个“+1”按钮,当用户点击按钮时会修改states,ReactJs在states变化时的”React”就是再次调用render函数,然后用新输出更新浏览器的dom。

可能你会问,props和states不就是Model吗?是的,可以理解成Model,但此Model非彼Model,props和states都是为View服务的而非和View平起平坐。

可能你还会问,为啥不把props和states合并成一个对象?要回答这个问题,就涉及到复杂视图的场景。想想看,当视图内的元素不断增加时,代码上如何处理,还要在一个render函数里折腾吗?肯定不会。我猜你已经想到了,要把大问题拆小。ReactJs给出的解决方法就是把大视图拆成若干个小视图,每个视图都有自己的render函数,在JSX中可以直接使用视图标签。看一个例子。

var Score = React.createClass({  
  initialState: function() {  
    return {amount: 1000};  
  },  


  function handleClickAdd() {  
    this.setState({amount: this.states.amount + 1});  
  }  


  render: function() {  
    var title = ’Hello, ' + this.props.name;  
    var description = 'You have ' + this.states.amount + ' score now.';  


    return (  
      <div className="score-board">  
         <h1>{title}</h1>  
         <p>{description}</p>  
         <button onClick={handleClickAdd}>+1</button>  
      </div>  
    );  
  }  
});  


var ScoreList = React.createClass({  
  render() {  
    return (  
      <ul className="score-list">  
        <li><Score name="Tom" /></li>  
        <li><Score name="Jerry" /></li>  
      </ul>  
    );  
  }  
});  


ReactDOM.render(  
  <ScoreList />,  
  document.getElementById('content')  
);

这个例子中有两类View,分别是Score和ScoreList。ScoreList的render函数中使用Score标签并给出配置项name的值。详细看一下Score,ReactJs提供createClass方法定义视图,在render函数中通过this.props访问外部传入的配置项,通过this.states访问视图内部的状态。从意图上看,props外部传入视图的配置项,拥有者是父视图,视图内部只能读取配置项,states的拥有者是视图自身。

区分props和states的结果就是,子视图没办法直接改变父视图,视图改变一定是自触发改变的视图开始向子视图传播。对上面的例子,当Tom的Score改变时,ScoreList其他部分一定不会改变,所以视图更新从Tom的Score视图开始就可以,这就保证了能更高效地计算视图变化,再加上VirtualDom的使用,使ReactJs的效率大大超过其他框架。

当子视图需要改变父视图时,也一定是从父视图开始向下更新。假如上面的例子中ScoreList还有平均分的视图,当Tom的分数改变时,需要更新ScoreList中的平均分。这就需要Score视图在处理”+1”输入时把变化通知到ScoreList,做法时给Score增加配置项,ScoreList中定义更新平均分的函数并把函数作为配置项传给Score。当ScoreList更新时,因为Jerry的props和states都没变化,所以Jerry的Score视图不需要更新。

这就是ReactJs的全部秘密了(不过Web前端本身是一个复杂系统,你还需要了解更多其他内容)。


原文发布于微信公众号 - 思特沃克(ThoughtWorks)

原文发表时间:2016-05-05

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏JackieZheng

AngularJS入门心得3——HTML的左右手指令

  在《AngularJS入门心得1——directive和controller如何通信》我们提到“AngularJS是为了克服HTML在构建应用上的不足而设计...

21550
来自专栏闻道于事

动态增加表单元素并获取元素的text和value提交

以上是效果图 需求是这样的: 专家设置好条件,然后设备检测到达到相应的条件之后,设备发出提醒给用户。 这就需要专家设置好能看懂的条件之后,然后把给专家看的,正常...

795110
来自专栏我的小碗汤

爬取珍爱网后用户信息展示

golang爬取珍爱网,爬到了3万多用户信息,并存到了elasticsearch中,如下图,查询到了3万多用户信息。

21840
来自专栏IMWeb前端团队

Vim 初探

都说Vim是编辑器之神,一直也觉得vim的编码非常酷炫~ 但是作为一个编辑器之神, 却一直保持着一个非常高傲的姿态,不像打开一个记事本,一个智商正常的人瞬间就...

228100
来自专栏腾讯IVWEB团队的专栏

Object.observe 简介

Object.observe 是一个提供数据监视的API,在chrome中已经可以使用。是 ECMAScript 7 的一个提案规范,官方建议的是“谨慎使用”级...

45900
来自专栏菩提树下的杨过

解决JQuery中的ready函数冲突

jQuery确实是一个提高前端开发效率的好框架(虽然很多大牛们都说它效率不咋地),但是用好它有时候并不容易,也许你也遇到过以下情况: 一个aspx页面通常可以包...

21080
来自专栏叁金大数据

自学Python七 爬虫实战一

  此文承接上文,让我们写一个简简单单的爬虫,循序而渐进不是吗?此次进行的练习是爬取前5页什么值得买网站中的白菜价包邮信息。包括名称,价格,推荐人,时间。

16710
来自专栏前端桃园

30分钟精通React今年最劲爆的新特性——React Hooks

你还在为该使用无状态组件(Function)还是有状态组件(Class)而烦恼吗? ——拥有了hooks,你再也不需要写Class了,你的所有组件都将是Func...

13520
来自专栏知道一点点

用js+cookie实现商城的购物车功能

<input name="buy" type="image" alt="第一个商品" src="images/buy.gif" align="middle" o...

32420
来自专栏王贝珊的专栏

你了解 Typescript 吗

TypeScript 是 JavaScript 的超集,带来了诸多新特性:可选的静态类型、类型接口、在 ES6 和 ES7 被主流浏览器支持之前使用它们的新特...

64610

扫码关注云+社区

领取腾讯云代金券