Структура однострочного приложения "Магистраль" и "Реакт"
Я использую backbone.js
для большинства моих проектов с интерфейсом JavaScript до сих пор, но после того, как узнал о Facebook react.js
, я заинтересовался и начал сотрясаться.
Мне интересно, должен ли я использовать класс Backbone.View
больше или заменить каждый "вид" на "компонентный" компонент - даже "базовый вид", который макетирует страницу...
Я нашел несколько сообщений в interwebs, которые все еще использовали Backbone.View
- другие, на которые я наткнулся только на созданные классы React.
Возможно, кто-то может указать мне в правильном направлении... что использовать, когда и как наилучшим образом реализовать несколько "страниц/состояний" в одностраничном приложении, а не только обычное (я могу больше это выдерживать). Пример TODO.
Вот код, который я придумал:
Базовый ресурс:
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;
});
Но я не совсем доволен этой настройкой. Любой вход приветствуется.
Ответы
Ответ 1
Не держите ссылку на такой компонент, как вы. Если необходимо использовать refs или еще лучше, просто отрисуйте компонент в обратном вызове. React проверит, нужно ли обновлять 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});
}
);
Изменить:
Поскольку логика в BaseView
очень полезна для логики в Router
, имеет смысл держать их в одном файле.
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});
Ответ 2
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;
});