【发布时间】:2014-04-06 13:06:54
【问题描述】:
我不知道是 React 还是 Meteor 问题,也许两者都有,但我目前正在使用这两个框架构建一个网络应用程序,我正面临程序员的问题。我不是 Javascript 开发人员,而是 Java 开发人员(我每天使用 GWT),所以也许我犯了一些菜鸟错误。
我的应用程序不断增长,我有越来越多的 React 组件,大约二十个左右。既然我的观点很好,我已经为我的组件添加了一些功能,但事实证明我在 react 组件中添加了越来越多的逻辑,我认为这违反了 MVC 原则。
但是,我不知道如何移动“流星控制器组件”中的逻辑。现在,我使用 Meteor 作为模型,仅此而已。我多次看到这个Pete Hunt's talk 以及他如何构建他的应用程序,但它只有一个“简单”组件。
事实上,如果没有 React,视图将在 html 文件中,使用模板定义。控制器将在 js 文件中,并且逻辑似乎在那里。我可以清楚地看到 view 和 controller 之间的分割。
Html 文件(来自排行榜示例):
<template name="leaderboard">
...
</template>
<template name="player">
<div class="player {{selected}}">
...
</div>
</template>
Javascript 文件(来自排行榜示例):
...
Template.leaderboard.players = function () {
return Players.find({}, {sort: {score: -1, name: 1}});
};
Template.leaderboard.selected_name = function () {
var player = Players.findOne(Session.get("selected_player"));
return player && player.name;
};
...
由于 React 是 javascript,因此将我们想要的所有内容放入 React 组件中真的很容易也很诱人。
我知道这些框架对每个人来说都是相对较新的,但我想知道是否存在一些关于如何设计这样的 MVC 应用程序以便拥有灵活和可维护的 Web 应用程序的约定,有什么要遵循的准则吗?我不是在寻找“最好”的方法,而是在寻找一些意见。
注意:我故意没有在这里放很多代码以不专注于它,但可以随意用任何你想要的东西(代码、架构、链接......)来说明你的答案。
这是我正在做的一个例子。在这个例子中,一切都在反应类中完成,也许这是最好的方法,也许不是,我需要你的想法。
总而言之,它从作为输入的数组(类似于 [{name: itemName1, type:itemType1}, {name: itemName2, type:itemType2} ... ] 生成如下视图:
- 项目名称1
- 项目名称2
- ...
每个项目根据其类型作为自己的样式。然后通过输入文本框,用户可以通过这个列表进行搜索,它过滤列表并生成一个由匹配元素组成的新列表(搜索算法不正确,将被更改)。此外,还有一些带有特定键盘键的附加命令。一切正常,但你可以注意到,一切都在反应类中,我不知道如何将 Meteor 与 React 结合起来。
流星文件:
if (Meteor.isClient) {
Meteor.startup(function() {
//Build the view
React.renderComponent(
<Search items={initialItems}/>,
document.getElementById('main')
);
});
}
反应文件:
Search = React.createClass({
getInitialState : function() {
return (
{
items : flat(this.props.items),
active : 0
}
);
},
setListVisibility: function(visibility) {
this.refs.list.getDOMNode().style.visibility = visibility;
},
onchangeHandler: function() {
var re = new RegExp(this.refs.search.getDOMNode().value, "i");
var res = [];
//filter on props.items and not state.items
flat(this.props.items).map(function(item){
if(item.name.search(re) >= 0)
res.push(item);
});
this.setState({ items : res, active : 0});
},
onkeydownHandler: function(event){
if(event.key == "ArrowDown" || event.key == "ArrowUp"){
var shift = event.key == "ArrowDown" ? 1 : -1;
var newActive = this.state.active + shift;
if(newActive >= 0 && newActive < this.state.items.length)
this.setState({ active : this.state.active + shift });
} else if(event.key == "ArrowRight"){
if(this.state.items.length > 0){
var item = this.state.items[this.state.active];
var newItems = retrieveItem(this.props.items, item.name, typeToSubType[item.type]);
newItems = flat(newItems);
if(newItems.length > 0)
this.setState({ items : newItems, active : 0 });
}
} else if(event.key == "ArrowLeft"){
this.setState({ items : flat(this.props.items), active : 0});
} else if(event.key == "Enter"){
if(this.state.items.length > 0){
var item = this.state.items[this.state.active];
console.log("Add "+item.name+" "+item.type+" to the view");
}
}
},
render: function () {
return (
<div>
<nav className="navbar navbar-default" role="navigation">
<div className="container-fluid">
<div className="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<form className="navbar-form navbar-left" role="search">
<div className="form-group">
<input ref="search" type="text" className="form-control" placeholder="Search" size="100"
onChange={this.onchangeHandler}
onKeyDown={this.onkeydownHandler}
onFocus={this.setListVisibility.bind(this, "visible")}
onBlur={this.setListVisibility.bind(this, "hidden")}/>
</div>
</form>
</div>
</div>
</nav>
<List ref="list" items={this.state.items} active={this.state.active}/>
</div>
);
}
});
List = React.createClass({
render: function () {
var createItem = function(item, index) {
var cl = "list-group-item";
if(index == this.props.active)
cl += " active";
var gly = "glyphicon ";
switch(item.type){
case "dimension":
gly += "glyphicon-certificate";
break;
case "hierarchy":
gly += "glyphicon-magnet";
break;
case "level":
gly += "glyphicon-leaf";
break;
case "measure":
gly += "glyphicon-screenshot";
break;
}
return (<a href="#" className={cl} key={item.type+"/"+item.name}>
<span className={gly}></span>{" "}{item.name}
</a>);
};
return (
<div className="list-group search-list">
{this.props.items.map(createItem, this)}
</div>
);
}
});
【问题讨论】:
-
你能把你目前得到的东西发布到公共回购吗?
-
我在帖子中添加了我主要项目中的一段代码。希望它足够可读。
-
如果您可以将问题的复制品上传到公共存储库,您可能会更幸运地获得帮助。
-
在将两者放在一起方面,这可能会有所帮助 - Peter Hunt,React 和 Meteor + 函数式编程 - youtube.com/watch?v=qqVbr_LaCIo
标签: javascript meteor reactjs