Подтвердить что ты не робот

Как сделать React и Meteor подходящими вместе

Я не знаю, больше ли это 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>
            );
    }
});
4b9b3361

Ответ 1

Ваш подход звучит: Meteor для модели и React для View и ViewController.

Любая функциональность, не имеющая ничего общего с презентацией, должна быть в модели (бизнес-логика, правила проверки и т.д.).

Все, что связано с представлением и ответом на ввод пользователя, должно быть в React (вход, выход проверки и т.д.).

Ответ 2

Сегодня вы можете рассмотреть этот приятный мир кода: https://github.com/reactjs/react-meteor

Этот репозиторий определяет пакет Meteor, который автоматически интегрирует структуру рендеринга React как на клиенте, так и на сервере, чтобы дополнить или заменить стандартную систему шаблонов Handlebars.

Ответ 3

По сравнению с Meteor 1.3 существует официально поддерживаемый способ интеграции React with Meteor. Поэтому для тех, кто сегодня споткнется по этому вопросу, здесь ответ Meteor 1.3+:

Чтобы использовать React в качестве слоя просмотра Meteor, сначала добавьте пакеты React из npm:

meteor npm install --save react react-dom

Теперь вы можете просто импортировать React и использовать его в своем проекте. Чтобы создать простой компонент React, создайте простой контейнер HTML:

клиент /main.html

<body>
  <div id="app"></div>
</body>

И сделайте в нем свой компонент React:

клиент /main.jsx

import React from 'react';
import { Meteor } from 'meteor/meteor';
import { render } from 'react-dom';

class HelloWorld extends React.Component {
  render() {
    return <p>Hello World!</p>;
  }
}

Meteor.startup(() => {
  render(<HelloWorld />, document.getElementById('app'));
});

Чтобы использовать реактивные источники данных Meteor, такие как коллекции Minimongo в компонентах React, вы должны использовать пакет react-meteor-data.

Подробнее в официальном руководстве Meteor