Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

structure of a Backbone and React single page app

I've been using backbone.js for most of my frontend JavaScript projects so far, but after hearing about Facebook's react.js I got interested and started poking around.

I'm wondering whether or not I'm supposed to use the Backbone.View class anymore or replace every "view" with a react "component" - even the "base-view" that's layouting the page ...

I found some posts in the interwebs that still used Backbone.Views - others I stumbled upon only created React-classes.

  • http://www.thomasboyt.com/2013/12/17/using-reactjs-as-a-backbone-view.html
  • https://usepropeller.com/blog/posts/from-backbone-to-react/
  • http://blog.mayflower.de/3937-Backbone-React.html
  • https://medium.com/react-tutorials

Maybe someone can point me in the right direction ... what to use when and how to best implement multiple "pages/states" in single page app and not just the usual (I can stand it anymore) TODO example.

Here some code that I came up with:

Backbone init stuff:

require(
  [
    "jsx!app/view/base",
    "react",
    "app/router",
    "backbone"
  ],
  function (BaseView, React, Router, Backbone) {
    "use strict";

    var router = new Router();
    var base = new BaseView({router: router});

    React.renderComponent(base, document.getElementById("page"));

    router.on("route", function(action) {
      base.setProps({path: action});
    });

    Backbone.history.start({pushState: true});
  }
);

app/router:

define(function(require) {

  "use strict";

  var Backbone = require("backbone");

  /**
   *
   */
  var Router = Backbone.Router.extend({
    routes: {
      "": "home",
      "test": "test",
      "*error": "404"
    }
  }); // end Router


  return Router;
});

app/view/base.jsx:

define(function(require) {

  "use strict";

  var React = require("react");

  var mixins = require("app/utils/mixins");

  var Header = require("jsx!app/view/header");
  var ContentHome = require("jsx!app/view/content_home");
  var ContentTest = require("jsx!app/view/content_test");
  var ContentLogin = require("jsx!app/view/content_login");

  /**
   *
   */
  var BaseView = React.createClass({

    render: function() {
      var content;

      switch (this.props.path) {
        case "home":
          content = <ContentHome />
          break;
        case "test":
          content = <ContentTest />
          break;
        case "login":
          content = <ContentLogin />
          break;

        case "404":
        default:
          content = "Error, page not found";
          break;
      } 

      return (
        <div id="base" onClick={this.onClick}>
          <Header />
          {content}
        </div>
      );
    },

    onClick: function(event) {
      if (event.target.tagName.toLowerCase() === "a" &&
          event.target.className === "main") {
        event.preventDefault();
        this.props.router.navigate(event.target.pathname, {trigger: true});
      }
    }

  }); // end BaseView

  return BaseView;
});

But I'm not completely pleased with this setup. Any input is welcome.

like image 841
Philipp Kyeck Avatar asked Feb 26 '14 20:02

Philipp Kyeck


People also ask

Is React good for single page application?

React is great for single page applications because it allows developers to create applications that are mobile first and responsive. React allows developers to create applications that are fast and easy to update, which is great for mobile applications.

What is backbone framework?

Backbone. js is a model view controller (MVC) Web application framework that provides structure to JavaScript-heavy applications. This is done by supplying models with custom events and key-value binding, views using declarative event handling and collections with a rich application programming interface (API).

Is Backbone JS frontend or backend?

Backend Synchronization BackboneJS is use with the front-end and back-end systems, allows the synchronization with the backend to provide support to RESTful APIs.


2 Answers

Don't hold a reference to a component like you are. If needed use refs or better yet, just render the component in the callback. React will check if it needs to update the DOM.

require(
  [
    "jsx!app/view/base",
    "react",
    "backbone"
  ],
  function (BaseView, React, Backbone) {
    "use strict";

    var router = Backbone.Router.extend({
      routes: {
        "": "home",
        "test": "test",
        "login": "login",
        "*error": "404"
      }
    }).on('route', function(action) {
      React.renderComponent(
        <BaseView router={router} path={action} />,
        document.getElementById("page")
      );
    });

    Backbone.history.start({pushState: true});
  }
);

Edit: Since the logic in BaseView is very coupeld to the logic in Router, it makes most sense to keep them in the same file.

var BaseView = React.createClass({
  render: function() {
    return (
      <div id="base" onClick={this.onClick}>
        <Header />
        {this.props.children}
      </div>
    );
  },

  onClick: function(event) {
    if (event.target.tagName.toLowerCase() !== "a") return;
    if (event.target.className !== "main") return;

    event.preventDefault();
    this.props.router.navigate(event.target.pathname, {trigger: true});
  }
});

app/router:

var router = Backbone.Router.extend({
  routes: {
    "": "home",
    "test": "test",
    "login": "login",
    "*error": "404"
  }
}).on('route', function(action) {
  var pathMapping = {
    "home": ContentHome,
    "test": ContentTest,
    "login": ContentLogin
  };
  var Content = pathMapping[action] || Content404;

  React.renderComponent(
    <BaseView router={router}>
      <Content />
    </BaseView>,
    document.getElementById("page")
  );
});

Backbone.history.start({pushState: true});
like image 87
Yazad D Avatar answered Oct 06 '22 18:10

Yazad D


  var BaseView = React.createClass({
    pathToComponent: function(){
        var paths = {
             'home': ContentHome,
             'login': ContentLogin
        };
        return paths[path] || Content404
    },
    render: function() {
      var ContentComponent = this.pathToComponent(this.props.path);
      return (
        <div id="base" onClick={this.onClick}>
          <Header />
          <ContentComponent />
        </div>
      );
    },

  }); // end BaseView

  return BaseView;
});
like image 41
Khaled Jouda Avatar answered Oct 06 '22 18:10

Khaled Jouda