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 "ponent" - even the "base-view" that's layouting the page ...
I found some posts in the interwebs that still used Backbone.View
s - others I stumbled upon only created React-classes.
- .html
- /
- .html
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 pletely pleased with this setup. Any input is wele.
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 "ponent" - even the "base-view" that's layouting the page ...
I found some posts in the interwebs that still used Backbone.View
s - others I stumbled upon only created React-classes.
- http://www.thomasboyt./2013/12/17/using-reactjs-as-a-backbone-view.html
- https://usepropeller./blog/posts/from-backbone-to-react/
- http://blog.mayflower.de/3937-Backbone-React.html
- https://medium./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 pletely pleased with this setup. Any input is wele.
Share Improve this question edited Feb 27, 2014 at 11:04 Philipp Kyeck asked Feb 26, 2014 at 20:55 Philipp KyeckPhilipp Kyeck 18.9k19 gold badges88 silver badges125 bronze badges 2- I wrote a similar answer here: stackoverflow./a/22063571/960178. Tell me if that helps? – chenglou Commented Feb 27, 2014 at 9:06
- thanks for the link - your answer looks pretty much like my approach. – Philipp Kyeck Commented Feb 27, 2014 at 10:26
2 Answers
Reset to default 2Don't hold a reference to a ponent like you are. If needed use refs or better yet, just render the ponent 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});
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;
});