如何使React和Meteor融合在一起

时间:2014-03-04 19:42:29

标签: javascript meteor reactjs

我不知道它是否更像 React Meteor 关注,可能两者兼而有之,但我目前正在使用这两个框架构建一个Web应用程序,我正面临着一个程序员问题。我不是Javascript开发人员,而是Java开发人员(我每天使用GWT),所以也许我犯了一些新手错误。

我的应用程序不断增长,我有越来越多的React组件,大约20个左右。既然我有一个很好的视图,我已经为我的组件添加了一些功能但是它出现了我在反应组件中添加了越来越多的逻辑,我相信这是针对MVC原则的。

但是,我不知道如何移动“Meteor控制器组件”中的逻辑。现在,我使用Meteor作为它的模型,而这几乎就是全部。我多次看到这个Pete Hunt's talk以及他如何构建他的应用程序,但它只有一个“简单”组件。

事实上,如果没有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应用程序以便拥有灵活且可维护的Web应用程序,遵循任何指导方针?我并不是在寻找“最佳”方式,而是寻求一些意见。

注意:我故意没有在这里放置很多代码而不关注它,但随意用你想要的任何东西来解释你的答案(代码,架构,链接......)。


这是我正在做的一个例子。在这个例子中,一切都是在反应类中完成的,也许这是最好的方法,也许不是,我需要你的想法。

总而言之,它会从作为输入的数组中创建一个元素列表(Boostrap列表组)(类似于[{name:itemName1,type:itemType1},{name:itemName2,type:itemType2} ... ]生成如下视图:

  • itemName1
  • itemName2
  • ...

每个项目根据其类型自己的样式。然后通过输入文本框,用户可以通过此列表进行搜索,它会过滤列表并生成一个由匹配元素组成的新列表(搜索算法不正确并将被更改)。另外,还有一些带有某些键盘键的命令。一切正常,但你可以注意到,所有都在反应类中,我不知道如何使用反应来适应Meteor。

流星文件:

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>
            );
    }
});

3 个答案:

答案 0 :(得分:7)

你的方法很合理:模型的Meteor和View和ViewController的React。

任何与演示无关的功能都应该在模型中(业务逻辑,验证规则等)。

与演示和响应用户输入有关的任何内容都应该在React(输入,验证输出等)中。

答案 1 :(得分:2)

今天你可以考虑这个代码的和平: https://github.com/reactjs/react-meteor

此存储库定义了一个Meteor软件包,可自动在客户端和服务器上集成React渲染框架,以补充或替换默认的Handlebars模板系统。

答案 2 :(得分:2)

从Meteor 1.3开始,有一种官方支持的将React与Meteor集成的方法。因此,对于今天绊倒这个问题的人来说,这是Meteor 1.3+答案:

要将React用作Meteor的视图图层,请先从npm添加React包:

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'));
});

要在React组件中使用反应性Meteor数据源(如Minimongo集合),您应该使用react-meteor-data包。

the official Meteor guide

了解更多