在上篇文章中,我们基于Meteor1.3和React搭建了一个最简单的应用。我们学习了如何通过NPM包添加React还有如何使用FlowRouter和React Mounter挂载React组件。
这篇文章中,我们继续以MeteoRain为例,讲解如何集成React和Meteor的数据系统。也就是说,我们将讲解如何通过订阅获取数据然后基于数据渲染组件。
React Container模式
在开始之前,我们先来讲一下React Container模式,这种模式能帮助你轻松地分离数据层和表现层。
看一看下面这个截图:
我们有一个名为BlogPost的组件包含UI,然后我们使用一个叫做「容器组件」的东西来获取数据。接着这个容器会通过props将数据传入UI组件。
Let's Compose Some React Containers
创建Posts集合
我们在lib/collections.js中添加一个名为Posts的集合:
Posts = new Mongo.Collection('posts');
添加虚拟数据
有了Posts这个集合后,我们来添加一些虚拟数据,也称为种子数据。我们在server/configs/initial_adds.js添加如下代码:
if (!Posts.findOne()) {
for (let lc = 1; lc <= 10; lc++) {
const title = `This is the post title: ${lc}`;
const category = lc % 2 ? "public" : "private";
const content = `Post ${lc}'s content is great!`;
Posts.insert({title, category, content});
}
}
发布数据
这里我们从名为Posts的集合中获取MongoDB记录,下面是我们要使用的发布。首先删除autopublish和insecure包:
meteor remove autopublish insecure
然后添加发布:
Meteor.publish('posts.list', function () {
const selector = {
category: {$ne: "private"}
};
const options = {
fields: {_id: 1, title: 1},
sort: {createdAt: -1},
limit: 10
};
return Posts.find(selector, options);
});
注意到,为方便起见,这里所有lib和server端代码我们都没有使用ES6的import和export进行模块化的处理,之后随着应用复杂度的增加我们会逐步重构。
UI组件
我们接下来要有一个渲染帖子的组件,代码如下:
import React from 'react';
const PostList = ({posts}) => (
This is the post list
{posts.map(({_id, title}) => (
-
{title}
))}
);
export default PostList;
这里我们使用的是一个函数式无状态组件。它会通过props传输数据来渲染UI。
构建容器
现在我们来创建一个容器来获取数据。为此,我们需要使用NPM包react-komposer,它是一个通用的React容器构建库。
import {composeWithTracker} from 'react-komposer';
import PostList from '../components/post_list.jsx';
function composer(props, onData) {
const handle = Meteor.subscribe('posts.list');
if(handle.ready()) {
const posts = Posts.find({}, {sort: {_id: 1}}).fetch();
onData(null, {posts});
};
};
export default composeWithTracker(composer)(PostList);
正如你所见,我们的订阅和数据获取逻辑写在composer函数中。这个composer函数在Tracker之中运行。所以你可以在这个函数中编写任何响应式代码。
一旦你获取了数据,你可以像这样调用onData函数:
const posts = Posts.find({}, {sort: {_id: 1}}).fetch();
onData(null, {posts});
composer函数的第一个参数是传递给容器的props。你可以使用容器来加载数据。
然后,我们这样构建容器:
export default composeWithTracker(composer)(PostList);
最后你将得到一个React组件。
渲染容器
现在我们来渲染容器。确保你渲染的是容器,而非UI组件:
import React from 'react';
import {mount} from 'react-mounter';
import Layout from './components/layout.jsx';
import Welcome from './components/welcome.jsx';
import PostList from './containers/post_list';
FlowRouter.route("/", {
name: "home",
action() {
mount(Layout, {
content:
});
}
});
FlowRouter.route("/posts", {
name: "postList",
action() {
mount(Layout, {
content:
});
}
});
一旦渲染之后,这是我们在React Dev tools中看到的画面。
正如你看到的那样,我们的UI组件被包裹在容器中。容器通过props传输数据到UI组件中。
最终,我们可以看到,category为private的帖子不会在PostList中显示。
总结
在client目录下,我们主要有两个目录,分别是components和containers。components目录下存放的是.jsx文件,也就是实际上的React UI组件,而containers目录下存放的是.js文件,是通过composer函数处理导入的UI组件,使之能够方便地处理传入数据的逻辑。而router.jsx由于要挂载组件,用到了
这样的语法,所以也是.jsx文件。这里并没有完全地按照Mantra规范来执行,但是随着应用体系的增加,我们会逐步按照Mantra来规范客户端代码,从实际中体会Mantra的好处。
参考
- 原文链接:Using Meteor Data and React with Meteor 1.3 beta
- Github Repo: MeteoRain
- 流星雨网站:MeteoRain全栈开发 ,网站会在基本UI完成后发布。