本文來自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 Native和Meteor,并且能成功運(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)用他炊,試一下添加刪除帖子功能吧争剿!
創(chuàng)建 React Native App
在一個(gè)新的終端窗口輸入以下命令:
react-native init RNApp && cd RNApp
注意:此處React Native新版本用的是babel6
,可是有些依賴的庫并不是這個(gè)版本痊末,就會(huì)導(dǎo)致紅屏出錯(cuò)蚕苇,所以解決方案就是把這個(gè)所以babel刪了,升級依賴凿叠。
- 先刪除依賴包
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了,盡管它并沒做什么事炒刁。
我們可以點(diǎn)擊Increment和Decrement兩個(gè)按鈕恩沽,可以看到控制臺中的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)。
在下一篇文章中追城,我們會(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)一步的挖掘茶鉴。