Step9: MeteorのPublish/SubscribeをReactで使おう!
このステップではMeteorのPublish/Subscribe機構をReactで使う方法を学びます。
Publish / Subscribe
これまでコレクションにデータを追加すると、自動的に全てのクライアントにデータが送られていました。これはMeteorのアプリを新規作成した時に入っているautopublish
というパッケージのおかげです。
しかし、データベースのデータ量が多くなった時に取得するデータ量を制限したり、ユーザー毎にプライベートなデータを持たせ、他のユーザーにはデータを配信しないようにする等の制御が必要になることがあります。
その時に使えるのが Meteor の Publish / Subscribe という仕組みです。
Publish / Subscribe の機能を使うには、autopublish
パッケージを外す必要があります。以下のコマンドを実行しましょう。
$ meteor remove autopublish
続いて、MemosコレクションのPublish設定をサーバー側で行います。
$ mkdir -p imports/api/memos/server
$ touch imports/api/memos/server/publications.js
imports/api/memos/server/publications.js
import { Meteor } from 'meteor/meteor';
import { Memos } from '../memos.js';
Meteor.publish('memos.all', function memosAll() {
return Memos.find({});
});
サーバーのmain.jsでpublications
を読み込みます。
server/main.js
import { Meteor } from 'meteor/meteor';
import { Memos } from '../imports/api/memos/memos';
import '../imports/api/memos/methods';
import '../imports/api/memos/server/publications';
Meteor.startup(() => {
if (Memos.find().count() === 0) {
const data = [
{content: 'Memo 1'},
{content: 'Memo 2'},
{content: 'Memo 3'},
{content: 'Memo 4'},
{content: 'Memo 5'},
];
data.forEach(memo => Memos.insert(memo));
}
});
Publish設定が完了したら、AppContainerでSubscribeを行います。
imports/ui/containers/AppContainer.js
import AppLayout from '../layouts/AppLayout';
import { Memos } from '../../api/memos/memos';
import { createContainer } from 'meteor/react-meteor-data';
import { Meteor } from 'meteor/meteor';
import '../../api/memos/methods';
const createMemo = content => {
Meteor.call('Memos.insert', content);
};
const removeMemo = memoId => {
Meteor.call('Memos.remove', memoId);
};
const updateMemoContent = (memoId, content) => {
Meteor.call('Memos.update', memoId, content);
};
export default createContainer(() => {
const memosHandle = Meteor.subscribe('memos.all');
return {
loading: !memosHandle.ready(),
memos: Memos.find({}, {sort: {createdAt: -1}}).fetch(),
createMemo,
removeMemo,
updateMemoContent,
};
}, AppLayout);
最後にAppLayoutでSubscribe中のローディング表示を追加します。
imports/ui/layouts/AppLayout.js
import React from 'react';
import Header from '../components/Header';
import MemoList from '../components/MemoList';
export default class AppLayout extends React.Component {
constructor(props) {
super(props);
this.onClick = this.onClick.bind(this);
}
onClick() {
const { memos, createMemo } = this.props;
createMemo(`New memo ${memos.length + 1}`);
}
render() {
const { memos, removeMemo, updateMemoContent, loading } = this.props;
if (loading) {
return this.renderLoading();
}
return (
<div className="container">
<Header />
<button className="add-button" onClick={this.onClick}>Add</button>
<MemoList
memos={memos}
removeMemo={removeMemo}
updateMemoContent={updateMemoContent}
/>
</div>
);
}
renderLoading() {
return (
<div className="container">
<div className="loading">Now Loading...</div>
</div>
);
}
}
AppLayout.propTypes = {
loading: React.PropTypes.bool,
memos: React.PropTypes.array.isRequired,
createMemo: React.PropTypes.func.isRequired,
removeMemo: React.PropTypes.func.isRequired,
updateMemoContent: React.PropTypes.func.isRequired,
};
ブラウザでリロードを行うと、ローディングが表示された後、メモの一覧が表示されるようになります。