web-dev-qa-db-ja.com

ReactとMeteorを組み合わせる方法

それがReactまたはMeteorのどちらであるかはわかりませんが、現在、これら2つのフレームワークを使用してWebアプリを構築しており、プログラマーの問題に直面しています。 。私はJavascript開発者ではありませんが、Java開発者(私は毎日GWTを使用しています)なので、新人のミスを犯した可能性があります。

私のアプリは成長を続けており、Reactコンポーネントは、約20ほどあります。ビューが良好になったので、コンポーネントにいくつかの機能を追加しましたが、結局は反応コンポーネントにロジックをどんどん追加してください。これは、MVCの原則に反していると思います。

しかし、「Meteorコントローラーコンポーネント」のロジックを移動する方法がわかりません。現在、モデルにはMeteorを使用していますが、それだけです。私はこれを何度も見ました Pete Huntの話 そして彼がどのように彼のアプリケーションを構築したか、しかしそれはただ一つの「単純な」コンポーネントを持っています。

実際、Reactがなければ、ビューはテンプレートで定義されたhtmlファイルになります。コントローラはjsファイルにあり、ロジックはそこにあるように見えます。 split betweenviewcontrollerがはっきりとわかります。

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コンポーネントに入れるのは本当に簡単で魅力的です。

これらのフレームワークは誰にとっても比較的新しいことを知っていますが、柔軟で保守可能なWebアプリケーションを作成するために、このようなMVCアプリケーションを設計する方法について、いくつかの規則が存在するのではないかと思います。私はそれを行うための「最良の」方法を探しているのではなく、いくつかの意見を求めています。

注:ここでは、焦点を絞らないように意図的に多くのコードを配置しませんでしたが、必要なもの(コード、スキーマ、リンクなど)で自由に答えを説明してください。


これが私がしていることの例です。この例では、すべてがreactクラスで行われています。おそらくそれが最善の方法であるかもしれませんが、そうではないかもしれません。

要約すると、入力として指定された配列([{name:itemName1、type:itemType1}、{name:itemName2、type:itemType2} ...]のようなもの)から要素のリスト(Boostrapリストグループ)を作成し、次のようなビュー:

  • itemName1
  • itemName2
  • .。

タイプに応じた独自のスタイルとしての各アイテム。次に、入力テキストボックスを使用して、ユーザーはこのリストを介して検索を行うことができます。リストをフィルタリングし、一致する要素で構成される新しいリストを生成します(検索アルゴリズムが正しくないため、変更されます)。さらに、特定のキーボードキーを使用した追加のコマンドがあります。すべて正常に動作しますが、お気づきのように、すべてがReactクラスにあり、MeteorをReactに適合させる方法がわかりません。

流星ファイル:

if (Meteor.isClient) {
  Meteor.startup(function() {
    //Build the view
    React.renderComponent(
      <Search items={initialItems}/>,
      document.getElementById('main')
      );
  });
}

Reactファイル:

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

あなたのアプローチは健全です:モデルの場合はMeteor、ViewとViewControllerの場合はReact。

プレゼンテーションとは関係のない機能はすべてモデルに含める必要があります(ビジネスロジック、検証ルールなど)。

プレゼンテーションとユーザー入力への応答に関係するものはすべてReact(入力、検証出力など)にある必要があります。

7
jokeyrhyme

今日、あなたはこの素晴らしいコードの平和を考えることができます: https://github.com/reactjs/react-meteor

このリポジトリは、クライアントとサーバーの両方でReactレンダリングフレームワークを自動的に統合して、デフォルトのハンドルバーテンプレートシステムを補完または置換するMeteorパッケージを定義します。

Meteor 1.3の時点で、ReactをMeteorと統合するための公式にサポートされている方法があります。したがって、今日この質問に出くわした人のために、Meteor1.3 +の回答を次に示します。

ReactをMeteorのビューレイヤーとして使用するには、最初にReact npmからのパッケージを追加します:

meteor npm install --save react react-dom

これで、Reactをインポートして、プロジェクトで使用できます。単純なReactコンポーネントをレンダリングするには、単純なHTMLコンテナーを作成します。

client/main.html

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

そして、その中のReactコンポーネントをレンダリングします:

client/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コンポーネント内でMinimongoコレクションなどのリアクティブMeteorデータソースを使用するには、react-meteor-dataパッケージを使用する必要があります。

続きを読む公式の流星ガイド

2
Waiski