Я не знаю, больше ли это React или Meteor, возможно, и то, и другое, но сейчас я создаю веб-приложение с этими двумя фреймворками, и я смотрю проблема программиста. Я не разработчик Javascript, а разработчик Java (я использую ежедневный GWT), поэтому, возможно, я совершил некоторые ошибки новобранец.
Мое приложение продолжает расти, и у меня есть все больше и больше компонентов React, около двадцати или около того. Теперь, когда у меня есть представление, это хорошо, я добавил некоторые функции к моим компонентам, но, как оказалось, я добавляю все больше логики в реагирующие компоненты, которые, я считаю, противоречат принципам MVC.
Однако я не знаю, как переместить логику в "компонентах контроллера Meteor". Прямо сейчас, я использую Meteor для своей модели и что почти все. Я много раз видел этот Пит Хант и как он создал свое приложение, но у него есть только один "простой" компонент.
Фактически, без React, представление будет в html файлах, определенных шаблонами. Контроллер будет находиться в js файлах, и логика появится там. Я отчетливо вижу раздел между представлением и контроллером .
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, чтобы иметь гибкое и поддерживаемое веб-приложение, любые руководящие принципы, которые следует соблюдать? Я не ищу "лучший" способ сделать это, но для некоторых мнений.
Примечание. Я намеренно не поставил здесь много кода, чтобы не сосредоточиться на нем, но не стесняйтесь проиллюстрировать свой ответ тем, что вы хотите (код, схема, ссылки...).
Вот пример того, что я делаю. В этом примере все делается в классах реагирования, возможно, это лучший способ сделать это, может быть, нет, мне нужны ваши мысли.
Подводя итог, он создает список элементов (группу списка Boostrap) из массива, заданного в качестве ввода (что-то вроде [{name: itemName1, type: itemType1}, {name: itemName2, type: itemType2}... ], который генерирует представление, подобное:
- itemName1
- itemName2
- ...
Каждый элемент как собственный стиль в соответствии с его типом. Затем через текстовое поле ввода пользователь может выполнить поиск через этот список, он фильтрует список и генерирует новый, который составлен с соответствующими элементами (алгоритм поиска неверен и будет изменен). Кроме того, есть дополнительные команды с определенной клавишей клавиатуры. Все работает нормально, но, как вы можете заметить, все в классах реагирования, я не понимаю, как установить 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>
);
}
});