使用 ReactJS 作为 Backbone 的 view 实现

在 Venmo(电子商务公司)公司,我们开始将我们的前端重新设计并重写成一个清晰的,纯 Backbone 模式的代码结构。Backbone 是一个编码模式的灵活的框架(也就是 MVC 框架)。但是它的视图层最少被设计,只为视图层提供了少量的生命周期钩子函数。和 Ember.js 的组件和 AngularJS 的指令相比,它缺少很多将数据和视图层相关联的钩子函数,也没有起到层与层之前的分离的作用。

为此我们很吃惊,于是我们不仅使用 Backone 视图,也在开始探索编写我们 UI 的更高级的选择,我的目标是找到一个即能和 Backones 视图层交互的,又能在一个大型框架里将视图写数据绑定和限定作用域的框架。幸运的是,我的朋友 Scott 介绍了 React 给我,经过几个小时的折腾之后,React 给了我一个很深刻的印象。

概述

React 是 Facebook 用来创建隔离化组件的一个很新颖的 JavaSript 库。在很多方面,它和 Angular directives 或者 Polymer web 组件很相似。React 组件本质是是一个带有作用域的自定义 DOM 元素。不管是在 JavaScript 中还是在 DOM 中,它都不能和你的应用程序状态的其它部分进行直接交互。

React 最独特也是最有争议的部分是使用 JSX,JSX 把内嵌 JavaScript 代码中的 HTML 转换成可以解析的 JavaScript 代码。这是一个 React 组件,使用 JSX 来渲染 a 标签 :

/* @jsx React.DOM /
var component = React.createClass({
  render: function() {
    return <a href="http://venmo.com">Venmo</a>
  }
});

转换后的 JavaScript 代码:

/* @jsx React.DOM /
var component = React.createClass({
  render: function() {
    return React.DOM.a( {href:"http://venmo.com"}, "Venmo")
  }
});

由于有大量的编译 / 转换工具,集成 JSX 到你的工作流中是很容易的:

require-jsx,是一个用来加载 JSX 文件的 RequireJS 插件

reactify 是一个 JSX 文件的 Browserify 转换工具

grunt-react 使用 Grunt 编译 JSX 文件

JSX 是可以选的 - 如果你愿意,你可以使用 React.DOM DSL 来写你的模板, 尽管我仅在模板很简单时才推荐这么干。

在这篇文章中我不会教 React 的基础知识, 你可以参考 excellent React tutorial 来学习. 那篇文章有点长,不过在继续往下看之前还是有必要浏览一下的!

从 Backbone 视图中渲染组件

让我们创建一个非常基础的组件:一个连接,当点击的时候能触发点击事件处理函数。我们想要把这个组件作为 Backbone 视图的一部分进行渲染,而不是单独使用它。这个组件很容易创建:

var MyWidget = React.createClass({
  handleClick: function() {
    alert('Hello!');
  },
  render: function() {
    return (
      <a href="#" onClick={this.handleClick}>Do something!</a>
    );
  }
});

这段代码和上个例子的代码几乎一样,除了增加了 handleClick 函数来响应点击事件。现在我们唯一需要做的就是在 Backbone 视图中渲染它:

var MyView = Backbone.View.extend({
  el: 'body',
  template: '<div class="widget-container"></div>',
  render: function() {
    this.$el.html(this.template);
    React.renderComponent(new MyWidget(), this.$('.widget-container').get(0));
    return this;
  }
});
new MyView().render();

这就是我们完整的新组件:

/* @jsx React.DOM /
/ global React, Backbone, $ /
var MyWidget = React.createClass({
  handleClick: function() {
    alert('Hello!');
  },
  render: function() {
    return (
      <a href="#" onClick={this.handleClick}>Do something!</a>
    );
  }
});

组件 -> Backbone 通信

当然,要想真正利用 React 组件的优势,我们需要将 React 组件的变化通知到 Backbone。随便举个例子,假设当组件里的链接被点击的时候显示一些文本。不止如此,我们还想让文本位于组件的 DOM元素之外。

关于不同的组件之间如何通信,React 文档已经解释得很好了,但是没有很明显地说明子组件如何跟Backbone 父视图交互。不过,有个简单容易的方式通信:我们可以通过组件的属性绑定一个事件处理器。

这里有个例子程序,JSX 代码:

function anEventHandler() { ... }
React.RenderComponent(<MyComponent customHandler={anEventHandler} />,
                      this.$('body').get(0));

我们可以在 Backbone view 里做同样的事,但我们直接用 class,不使用 JSX:

var MyView = Backbone.View.extend({
  el: 'body',
  template: '<div class="widget-container"></div>' +
            '<div class="outside-container"></div>',
  render: function() {
    this.$el.html(this.template);
    React.renderComponent(new MyWidget({
      handleClick: this.clickHandler.bind(this)
    }), this.$('.widget-container').get(0));
    return this;
  },
  clickHandler: function() {
    this.$(".outside-container").html("The link was clicked!");
  }
});

另外,在组件内部绑定 onClick 到事件处理器:

var MyWidget = React.createClass({
  render: function() {
    return (
      <a href="#" onClick={this.props.handleClick}>Do something!</a>
    );
  }
});

这里是更新过的完整的例子:

/* @jsx React.DOM /
/ global React, Backbone, $ /
var MyWidget = React.createClass({
  render: function() {
    return (
      <a href="#" onClick={this.props.handleClick}>Do something!</a>
    );
  }
});
var MyView = Backbone.View.extend({
  el: 'body',
  template: '<div class="widget-container"></div>' +
            '<div class="outside-container"></div>',
  render: function() {
    this.$el.html(this.template);
    React.renderComponent(new MyWidget({
      handleClick: this.clickHandler.bind(this)
    }), this.$('.widget-container').get(0));
    return this;
  },
  clickHandler: function() {
    this.$(".outside-container").html("The link was clicked!");
  }
});
new MyView().render();

再次说明,这是一个不太自然的例子,但是想象出一个更加实用的用例应该不难。

比如,在 Venmo 我们用 React 重新开发了“使用 Facebook 登录”按钮。实际的 Facebook API 调用发生在组件内部,但是组件所在的 view 针对不同的事件绑定了不同的处理函数。这些事件(比如“Facebook 认证通过”或者“ Facebook 已登出”)本质上是组件的“公共API”。React 也可以在事件中传递参数,以便在用户连接到 Facebook 的时候,Backbone view 可以获取到用户的 Facebook ID,同时把它附加到 user model 上。

Backbone与reactjs 组件通信

现在,我们知道了组件通信了,下一步,我们用 Backbone 模型来更新 reactjs 组件的状态,来作为一个例子,我们会让改变的模型字段反应到视图上面.这需要定义一些模板(虽然这比 Backbone 手动绑定视图强不了多少),但是在实践当中还是相当容易的。

首先: 我们创建一个小模型类:

var ExampleModel = Backbone.Model.extend({
  defaults: {
    name: 'Backbone.View'
  }
});

然后用一个简单的 React 组件显示 name 字段:

var DisplayView = React.createClass({
  render: function() {
    return (
      <p>
        {this.props.model.get('name')}
      </p>
    );
  }
});

尽管这个组件不能自已反应模型字段的更改,但是我们可以为模型加一个 change 监听事件,来告诉组件去重新渲染:

var DisplayView = React.createClass({
  componentDidMount: function() {
    this.props.model.on('change', function() {
      this.forceUpdate();
    }.bind(this));
  },
  render: function() {
    // ...
  }
});

然后我们增加另一个组件改变 name 字段:

var ToggleView = React.createClass({
  handleClick: function() {
    this.props.model.set('name', 'React');
  },
  render: function() {
    return (
      <button onClick={this.handleClick}>
        model.set('name', 'React');
      </button>
    );
  }
});

最后,我们创建一个模型,然后用 JSX 来渲染两个组件:

var model = new ExampleModel();
React.renderComponent((
  <div>
    <DisplayView model={model} />
    <ToggleView model={model} />
  </div>
), document.body);

例子到此结束, 完整的例子可以到这里观看http://runjs.cn/detail/eqituk3o

结论

Backbone + React 是一个神奇的组合。有其他几个博客有这样的讨论帖子:

Joel Burget 讨论 Khan Academy(可汗学院)对 React 的移植

Clay Allsopp 写的 Propeller 移植到 React 的帖子,包括一个非常酷的 React Mixin 被绑定到Backbone Model/Collection changes ,类似我们上面做的最后一个例子。

Paul Seiffert (require-jsx的作者)有另外一篇文章是关于用 React 取代 Backbone 的视图

React 也有一个 Backbone+React 的例子 TodoMVC app 值得试试。

当 React 还不成熟的时候,它是一个非常令人兴奋的库,看起来好像是可供生产使用的一个库了。它很容易分享和重用组件,我最感兴趣的是它与 Backbone 集成地如此之好,弥补了默认的视图逻辑。

文章转载自 开源中国社区[https://www.oschina.net]

时间: 2024-09-14 13:02:42

使用 ReactJS 作为 Backbone 的 view 实现的相关文章

Backbone中View之间传值的学习心得_javascript技巧

Backbone中的View就是用来展示由Model层传出的数据,或者在View里产生的一些数据,包括输入框中输入等产生的数据,由当前View传递到另外一个View层里,应该怎么办呢,我之前读到一位博主<Backbone View的三种通信方式 >写的尤为的清晰,在我实际的项目中,常常使用的也就是最后一种方式. 嘿嘿,分享知识是一件快乐的事情,我就直接借鉴表述一下如下: 直接用 Backbone 作为事件注册机, 代码如下: var ApplicationView = Backbone.Vie

Backbone View 之间通信的三种方式_javascript技巧

在上篇文章给大家介绍了Backbone中View之间传值的学习心得.本文重点给大家介绍Backbone View 之间通信的三种方式. 掌握一个 MVC 框架,最关键的一节就是掌握如何在各个 View 之间通信.之前用 Angular 时,觉得基于事件的通信方式 ($on, $emit, $boardcast) 或者 基于 service 的方式都非常好用.转战 Backbone 之后,由于对 Backbone 的事件机制理解不够且使用非常灵活,一直没找到一个好的通信方式.直到看见这篇文章,作者

讲解JavaScript的Backbone.js框架的MVC结构设计理念_基础知识

什么是Backbone.js?Backbone.js是十大JS框架之首,Backbone.js 是一个重量级js  MVC 应用框架,也是js MVC框架的鼻祖.它通过Models数据模型进行键值绑定及custom事件处理,通过模型集合器Collections提供一套丰富的API用于枚举功能,通过视图Views来进行事件处理及与现有的Application通过JSON接口进行交互. 简而言之,Backbone是实现了web前端MVC模式的js库 什么是MVC?MVC:后端服务器首先(过程1)通过

javascript样式-除了bootstrap,还有哪些比较好用的前端框架???

问题描述 除了bootstrap,还有哪些比较好用的前端框架??? 想了解更多的关于网站前端的框架,希望有大神可以指教,多多推荐,最好是在网站上可以学习的那种. 解决方案 angularjs knockoutjs reactjs extjs backbone.js easyui 解决方案二: jQWidgets,easyui

Backbone.js系列教程十:Backbone.View

在前几节中我们介绍了Backbone基础知识,如果你还没有阅读过,那么我建议你从第一节开始学习--Backbone.js系列教程一:Backbone.js初探,尤其希望你能完全理解构造Backbone对象相 关知识,这对于学习今后的内容有很大帮助.在接下来的几个小节中,我们将深入Backbone,讨论Backbone views.models和collections.相信大家在阅读前文之后,已经对Backbone.View.Backbone.Model. Backbone.Collection构

Backbone View入门

Backbone 是一个 JavaScript 框架,可用于创建模型-视图-控制器 (model-view-controller, MVC) 类应用程序和单页界面.它试图让 JavaScript 应用程序更清晰结构化,所涉及到的概念有  View, Event, Model, Collection 和 Router,所以新手刚开始接触 Backbone 反而会显得零乱了.再加上网上找来的一些起步教程一上来就把 Event, Model, Collection 或是 Router 揽上了.其实新手

backbone复杂model及父子view的数据流问题

问题描述 backbone复杂model及父子view的数据流问题 已搞明白,已搞明白,已搞明白,已搞明白,已搞明白,已搞明白,已搞明白,已搞明白,已搞明白,已搞明白,已搞明白,已搞明白,已搞明白,已搞明白,已搞明白,已搞明白,已搞明白,已搞明白,已搞明白,已搞明白,已搞明白,已搞明白,谢谢! 解决方案 backbone>>model复杂事件处理(Complex Event Processing)--6. 复杂事件处理总结复杂事件处理在金融证券行业的应用

简单了解Backbone.js的Model模型以及View视图的源码_基础知识

Backbone.Model 今天我们先来谈谈Backbone.js MVC 中的 M , Model是backbone的核心部分,包含着页面展示内容的数据,还有围绕着数据操作的各种 转换,校验,计算 ,权限控制,服务端交互等等操作,你可以通过 Backbone.Model.extend() 生成你的model , 当然生成的model也可以作为一个基类去向下扩展更多的model var People = Backbone.Model.extend({ }); var Man = People.

基于Reactjs实现webapp(加精)

git原文链接:https://github.com/my-fe/wiki/issues/1 由于最近的reactjs实在太火,而且距离第一版已经快2年的时间了,已经相对稳定和成熟了,基于这两个前提下,团队对reactjs及其他开源技术进行了相关调研,发现落地是可行的,我们有4名前端同学,从调研到上线,大概花了1个半月的时间,期间有踩一些坑,后面会说,整个开发总体来说是非常顺利的,下面进入正题~~ 产品简介 线上应用:mami.baidu.com 我们做的是一个移动端的单页webapp,可以在这