Meteor開發(fā)指南 — 使用Meteor作為React Native的實(shí)時(shí)后端

本文來自Differential Blog氛悬,不過文中示例代碼有不少bug,有些是版本問題,有些是npm包的問題窒盐,測試修改過后的Github示例代碼在此:https://github.com/loongmxbt/meteor-react-native-basic 啃奴。下面是正文部分潭陪。

Parse最近宣布停止服務(wù),許多公司會(huì)尋求它的替代品最蕾。這次Parse的關(guān)門會(huì)讓許多人不會(huì)首選BaaS產(chǎn)品依溯,轉(zhuǎn)而傾向于自行實(shí)現(xiàn)后端,比如說使用Meteor瘟则。

我們來談?wù)勅绾螌⒁粋€(gè)React Native的App連接到Meteor App(作為服務(wù)端)黎炉。這篇教程假設(shè)你已經(jīng)安裝好了React NativeMeteor,并且能成功運(yùn)行醋拧。如果你還沒有配置好React Native環(huán)境的話慷嗜,可以查看React Native中文文檔淀弹。

你可以通過這里看到完成好的app的源代碼,訪問Github庆械。

創(chuàng)建Meteor App

首先創(chuàng)建一個(gè)Meteor App:

meteor create meteor-app

然后刪除autopublish和insecure包薇溃,這通常是最佳實(shí)踐:

cd meteor-app && meteor remove autopublish insecure

然后添加random包:

meteor add random

然后刪除默認(rèn)生成的三個(gè)html,css缭乘,js文件:

rm meteor-app.*

接著按照如下的目錄和文件結(jié)構(gòu)創(chuàng)建:

  • /both/posts.js
  • /client/home.html
  • /client/home.js
  • /client/index.html
  • /server/app.js

我們馬上會(huì)逐一講解這些文件沐序。

為Meteor App增加功能

這會(huì)是一個(gè)非常簡單的app,其中演示的只是如何創(chuàng)建連接堕绩,訂閱數(shù)據(jù)和調(diào)用方法策幼,我們所要做的是創(chuàng)建一個(gè)Posts集合,給它一些初始種子數(shù)據(jù)逛尚,然后發(fā)布這個(gè)集合垄惧。然后在客戶端我們訂閱數(shù)據(jù),并返回一個(gè)總體文章的計(jì)數(shù)绰寞。用戶可以添加或者刪除文章到逊,這是我們要使用React Native模仿的功能。這里是代碼:

/both/posts.js文件中滤钱,我們創(chuàng)建Posts集合并且創(chuàng)建兩個(gè)Meteor方法:

Posts = new Mongo.Collection('posts');

Meteor.methods({  
  'addPost': function() {
    Posts.insert({title: 'Post ' + Random.id()});
  },

  'deletePost': function() {
    let post = Posts.findOne();
    if (post) {
      Posts.remove({_id: post._id});
    }
  }
})

/server/app.js中觉壶,我們創(chuàng)建初始數(shù)據(jù)并發(fā)布Posts集合:

Meteor.startup(function() {  
  if (Posts.find().count() === 0) {
    for (i = 1; i <= 10; i++) {
      Posts.insert({title: 'Post ' + Random.id()});
    }
  }
});

Meteor.publish('posts', function() {  
  return Posts.find();
});

/client/home.html中,我們創(chuàng)建一個(gè)最簡模板:

<template name="home">  
  <h1>Post Count: {{count}}</h1>
  <button id="increment">Increment</button>
  <button id="decrement">Decrement</button>
</template>  

/client/home.js中件缸,我們訂閱posts并創(chuàng)建模板helpers:

Template.home.onCreated(function() {  
  this.subscribe('posts');
});

Template.home.helpers({  
  count() {
    return Posts.find().count();
  }
});

Template.home.events({  
  'click #increment': function(e) {
    e.preventDefault();

    Meteor.call('addPost');
  },

  'click #decrement': function(e) {
    e.preventDefault();

    Meteor.call('deletePost');
  }
})

/client/index.html中铜靶,我們創(chuàng)建整體模板:

<head>  
  <title>meteor-app</title>
</head>

<body>  
  {{> home}}
</body>  

現(xiàn)在你就創(chuàng)建好了一個(gè)功能完備的Meteor App了,命令行輸入meteor啟動(dòng)應(yīng)用他炊,試一下添加刪除帖子功能吧争剿!

Meteor App

創(chuàng)建 React Native App

在一個(gè)新的終端窗口輸入以下命令:

react-native init RNApp && cd RNApp

注意:此處React Native新版本用的是babel6,可是有些依賴的庫并不是這個(gè)版本痊末,就會(huì)導(dǎo)致紅屏出錯(cuò)蚕苇,所以解決方案就是把這個(gè)所以babel刪了,升級依賴凿叠。

  1. 先刪除依賴包
rm -rf node_modules ncu -u npm install

2涩笤,修改package.json文件

"scripts": { 
    "clean:babelrc": "find ./node_modules -name react-packager -prune -o -name '.babelrc' -print | xargs rm -f", 
    "postinstall": "npm run clean:babelrc" 
}

當(dāng)然,還有一個(gè)比較簡單粗暴的解決方法盒件,就是直接刪除錯(cuò)誤提示中的.babelrc文件:

rm node_modules/react-deep-force-update/.babelrc

設(shè)置 React Native App

我們在生成的app中創(chuàng)建和修改2個(gè)文件蹬碧。

首先創(chuàng)建app/index.js

import React, {  
  View,
  Text,
  StyleSheet
} from 'react-native';

import Button from './button';

export default React.createClass({  
  getInitialState() {
    return {
      connected: false,
      posts: {}
    }
  },

  handleIncrement() {
    console.log('inc');
  },

  handleDecrement() {
    console.log('dec');
  },

  render() {
    let count = 10;
    return (
      <View style={styles.container}>
        <View style={styles.center}>
          <Text>Posts: {count}</Text>
          <Button text="Increment" onPress={this.handleIncrement}/>
          <Button text="Decrement" onPress={this.handleDecrement}/>
        </View>
      </View>
    );
  }
});

const styles = StyleSheet.create({  
  container: {
    flex: 1,
    justifyContent: 'center',
    backgroundColor: '#F5FCFF',
  },
  center: {
    alignItems: 'center'
  }
});

創(chuàng)建app/button.js

import React, {  
  View,
  Text,
  TouchableOpacity,
  StyleSheet
} from 'react-native';

export default React.createClass({  
  render() {
    let { text, onPress } = this.props;

    return (
      <TouchableOpacity style={styles.button} onPress={onPress}>
        <Text>{text}</Text>
      </TouchableOpacity>
    );
  }
});

const styles = StyleSheet.create({  
  button: {
    flex: 1,
    backgroundColor: '#eee',
    paddingHorizontal: 20,
    paddingVertical: 10,
    marginVertical: 10
  }
});

修改index.ios.js

import React, {  
  AppRegistry,
  Component
} from 'react-native';

import App from './app';

class RNApp extends Component {  
  render() {
    return <App />;
  }
}
AppRegistry.registerComponent('RNApp', () => RNApp);  

修改index.android.js

import React, {
  AppRegistry,
  Component
} from 'react-native';

import App from './app';

class RNApp extends Component {
  render() {
    return <App />;
  }
}
AppRegistry.registerComponent('RNApp', () => RNApp);

你現(xiàn)在已經(jīng)有了一個(gè)可以運(yùn)行的React Native App了,盡管它并沒做什么事炒刁。

React Native App

我們可以點(diǎn)擊Increment和Decrement兩個(gè)按鈕恩沽,可以看到控制臺中的log:

Console log

連接React Native應(yīng)用到Meteor服務(wù)器

現(xiàn)在到了有趣的部分了,我們來讓兩個(gè)app相互間通訊翔始,我們會(huì)使用node-ddp-client這個(gè)包罗心,你也可以使用其他類似的擴(kuò)展包片吊。

首先我們通過npm添加擴(kuò)展包:

npm install ddp --save

首先我們要導(dǎo)入ddp client這個(gè)庫并且初始化它。由于這是個(gè)開發(fā)應(yīng)用示例协屡,所以我們只使用到默認(rèn)配置俏脊。node-ddp-client的README闡述了一些其他ddp的配置。

app/index.js中:

import React, {  
  View,  
  Text,  
  StyleSheet  
} from 'react-native';

import Button from './button';

import DDPClient from 'ddp-client';  
let ddpClient = new DDPClient();

export default React.createClass({  
/*
 * Removed from snippet for brevity
 */
});

下一步我們真正連接到服務(wù)器肤晓。同樣在app/index.js中:

/*
 * Removed from snippet for brevity
 */

import DDPClient from 'ddp-client';  
let ddpClient = new DDPClient();

export default React.createClass({  
  getInitialState() {
    return {
      connected: false,
      posts: {}
    }
  },

  componentDidMount() {
    ddpClient.connect((err, wasReconnect) => {
      let connected = true;
      if (err) connected = false;

      this.setState({ connected: connected });
    });
  },

  /*
   * Removed from snippet for brevity
   */
});

我們現(xiàn)在就連接上了爷贫!你可以基于這些做更多的事情,但這里只講解最基本的場景补憾。這是你開始所需要的一切漫萄。

在React Native中訂閱

app/index.js中,發(fā)布你的訂閱盈匾。當(dāng)訂閱完成后腾务,目前我們只是更新state來獲取posts數(shù)據(jù)。

/*
 * Removed from snippet for brevity
 */

export default React.createClass({  
  getInitialState() {
    return {
      connected: false,
      posts: {}
    }
  },

  componentDidMount() {
    ddpClient.connect((err, wasReconnect) => {
      let connected = true;
      if (err) connected = false;

      this.setState({ connected: connected });
      this.makeSubscription();
    });
  },

  makeSubscription() {
    ddpClient.subscribe("posts", [], () => {
      this.setState({posts: ddpClient.collections.posts});
    });
  },

  /*
   * Removed from snippet for brevity
   */

  render() {
    let count = Object.keys(this.state.posts).length;
    return (
      <View style={styles.container}>
        <View style={styles.center}>
          <Text>Posts: {count}</Text>
          <Button text="Increment" onPress={this.handleIncrement}/>
          <Button text="Decrement" onPress={this.handleDecrement}/>
        </View>
      </View>
    );
  }
});

這很棒削饵,但是實(shí)時(shí)的東西怎么加進(jìn)去呢岩瘦?我們會(huì)使用一個(gè)最基本的方法來獲得實(shí)時(shí)性。

app/index.js中:

/*
 * Removed from snippet for brevity
 */
componentDidMount() {  
  ddpClient.connect((err, wasReconnect) => {
    let connected = true;
    if (err) connected = false;

    this.setState({ connected: connected });
    this.makeSubscription();
    this.observePosts();
  });
},

makeSubscription() {  
  ddpClient.subscribe("posts", [], () => {
    this.setState({posts: ddpClient.collections.posts});
  });
},

// This is just extremely simple. We're replacing the entire state whenever the collection changes
observePosts() {  
  let observer = ddpClient.observe("posts");
  observer.added = (id) => {
    this.setState({posts: ddpClient.collections.posts})
  }
  observer.changed = (id, oldFields, clearedFields, newFields) => {
    this.setState({posts: ddpClient.collections.posts})
  }
  observer.removed = (id, oldValue) => {
    this.setState({posts: ddpClient.collections.posts})
  }
},
/*
 * Removed from snippet for brevity
 */

在 React Native 中調(diào)用 Meteor 方法

那么如何在React Native應(yīng)用中添加和刪除文章呢窿撬?

app/index.js中:

handleIncrement() {  
  ddpClient.call('addPost');
},

handleDecrement() {  
  ddpClient.call('deletePost');
},

現(xiàn)在你就有了一個(gè)功能完備的启昧,簡單明了的React Native作為前端,Meteor作為后端的應(yīng)用劈伴。我希望這篇教程能讓你開啟編寫React Native+Meteor混合應(yīng)用的道路密末。你可以(應(yīng)該)使用一些其他框架,來管理應(yīng)用的狀態(tài)跛璧,比如Redux等严里,并且使用React的思想理念來構(gòu)造你的組件結(jié)構(gòu)。

Meteor React Native

在下一篇文章中追城,我們會(huì)講解如何將React Native應(yīng)用連接到Meteor的用戶系統(tǒng)刹碾。

當(dāng)然,目前這個(gè)Repo還有一點(diǎn)小問題漓柑,就是實(shí)時(shí)性只體現(xiàn)在RNApp -> Meteor App這里教硫,如果在Meteor App中修改叨吮,RNApp需要手動(dòng)刷新辆布,這里可能與node-ddp-client這個(gè)包的observe有關(guān),有待進(jìn)一步的挖掘茶鉴。

Meteor全棧開發(fā)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末锋玲,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子涵叮,更是在濱河造成了極大的恐慌惭蹂,老刑警劉巖伞插,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異盾碗,居然都是意外死亡媚污,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進(jìn)店門廷雅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來耗美,“玉大人,你說我怎么就攤上這事航缀∩碳埽” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵芥玉,是天一觀的道長蛇摸。 經(jīng)常有香客問我,道長灿巧,這世上最難降的妖魔是什么赶袄? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮抠藕,結(jié)果婚禮上弃鸦,老公的妹妹穿的比我還像新娘。我一直安慰自己幢痘,他們只是感情好唬格,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著颜说,像睡著了一般购岗。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上门粪,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天喊积,我揣著相機(jī)與錄音,去河邊找鬼玄妈。 笑死乾吻,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的拟蜻。 我是一名探鬼主播绎签,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼酝锅!你這毒婦竟也來了诡必?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤搔扁,失蹤者是張志新(化名)和其女友劉穎爸舒,沒想到半個(gè)月后蟋字,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡扭勉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年鹊奖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片涂炎。...
    茶點(diǎn)故事閱讀 40,664評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡嫉入,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出璧尸,到底是詐尸還是另有隱情咒林,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布爷光,位于F島的核電站垫竞,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏蛀序。R本人自食惡果不足惜欢瞪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望徐裸。 院中可真熱鬧遣鼓,春花似錦、人聲如沸重贺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽气笙。三九已至次企,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間潜圃,已是汗流浹背缸棵。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留谭期,地道東北人堵第。 一個(gè)月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像隧出,于是被迫代替她去往敵國和親踏志。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內(nèi)容