Introduction
In the last few weeks, I was very intrigued by React native. I kept seeing more and more articles like this one, so I decided to take a deeper dive into React Native and actually use it, for real.
Meteor is the framework I use at work, and I now have some experience with it. I thought about connecting the React Native application with a Meteor back-end. This article will show you how to get things started.
Creating the Meteor app
First things first, we will create a Meteor application.
meteor create serverMeteor
For now, that is all we need. We'll come back to that.
Creating our React Native app
I'll use the very useful create-react-native-app tool. You can get more info on this, check this link. It will also explain how to use the Expo client app to see your work, very useful!
So, we run a command like this:
create-react-native-app reactFront
Now, you'll have two folders. One named meteorServer that contains your Meteor application, and an other named reactFront where you will find your react-native application.
React-Native: Creating a simple PhoneBook
For the sake of brevity, we will create something simple. The user will have a form with two inputs. The first will take a name, the second a phone number.
After modifications, here is how App.js looks like:
import React from 'react';
import { StyleSheet, Text, View, TextInput, Button } from 'react-native';
export default class App extends React.Component {
constructor(){
super()
this.state = {
name: '',
number: ''
}
}
addPhoneNumber = () => {
console.log(this.state)
this.setState({
number: '',
name: ''
})
}
render() {
return (
<View style={styles.container}>
<TextInput
style={styles.input}
placeholder='Enter a name'
onChangeText={name => this.setState( {name} )}
value={this.state.name}/>
<TextInput
style={styles.input}
keyboardType='numeric'
placeholder='Enter a phone number'
onChangeText={number => this.setState( {number} )}
value={this.state.number}/>
<Button
onPress={this.addPhoneNumber}
title='Save Phone Number'/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
marginTop: 20
},
input: {
borderWidth: 2,
borderColor: 'gray',
height: 50,
margin: 10
}
});
I added two TextInput elements and a Button element. I also added some styles for the input. In React Native, we use StyleSheet.create({}) to control styles. Or you could style using the inline objects as in React.
On my iOS simulator it looks like this:
Ok, for now, when we click ( or tap ) on the button. Nothing happens. It logs the values in the console and reset them. Let's move on to the back-end.
Meteor: Preparing the method and publication
Go to the folder where your Meteor application is located. Mine was called serverMeteor.
Let's create a /imports folder, and inside this /imports, we'll add an /api folder. Just to follow the proper Meteor conventions.
Here is the plan: we will create a Meteor method that our React Native app will call when we click on the Save Phone Number button. This method will save the name and the number to the Meteor mongo database.
Then, we will create a publication that our React Native application will subscribe to. It will simply return all the entries we have. Let's go!
In /imports/api/, let's create a PhoneNumbers.js file that will hold our small back-end logic.
export const PhoneNumbers = new Mongo.Collection( 'phoneNumbers' )
Meteor.methods({
addPhoneNumber( data ){
PhoneNumbers.insert({
name: data.name,
number: data.number
}, err => {
if (err){
return err
} else {
return null
}
})
}
})
Meteor.publish( 'getAllNumbers', () => {
return PhoneNumbers.find({})
})
Nothing fancy here. We create our collection, our method addPhoneNumber and our publication getAllNumbers. And that's it for Meteor. Let's make the two applications talk to one another.
React Native: Adding react-native-meteor
Go back to the React Native folder. We will use the react-native-meteor package to connect both applications.
npm install --save react-native-meteor
Here are the changes we need to make:
- Call the addPhoneNumber method when we click our button.
- Subscribe to our getAllNumbers publication
- Display the numbers in a list
- Make sure our React Native app is aware of our Meteor application.
Let's start with the method call. If you've worked with Meteor/React before, this will look very familiar:
// In our App component
addPhoneNumber = () => {
const data = {
number: this.state.number,
name: this.state.name
}
Meteor.call('addPhoneNumber', data, err => {
if( err ){
console.log( err )
} else {
this.setState({
number: '',
name: ''
})
}
})
}
Next, let's subscribe to our publication. For this, we will wrap our App component in createContainer provided by react-native-meteor. Let's import it at the top of our file:
import Meteor, {Â createContainer } from 'react-native-meteor'
Good, now we will NOT export our App component, but the createContainer wrapper. Like so:
// The App Component will be defined above like so:
// class App extends React.Component{ ... }
export default createContainer( () => {
Meteor.subscribe('getAllNumbers')
return {
phoneNumbers: Meteor.collection('phoneNumbers').find({})
}
}, App) // Need to specify which component we are wrapping
Ok, that's done. So we will get the phone numbers in a nice array. We will display them in a list. Nothing fancy, we will use the FlatList component. Don't forget to import FlatList from react-native. Our render function will look like so:
// Still in the App component my friend
render() {
return (
<View style={styles.container}>
<TextInput
style={styles.input}
placeholder='Enter a name'
onChangeText={name => this.setState( {name} )}
value={this.state.name}/>
<TextInput
style={styles.input}
keyboardType='numeric'
placeholder='Enter a phone number'
onChangeText={number => this.setState( {number} )}
value={this.state.number}/>
<Button
onPress={this.addPhoneNumber}
title='Save Phone Number'/>
<FlatList
data={this.props.phoneNumbers}
keyExtractor={(item, index) => item._id}
renderItem={({item}) => (
<View>
<Text>{item.name} || {item.number}</Text>
</View>
)} />
</View>
);
}
FlatList takes the array of data and loops through it in the renderItem function. I'm just displaying the name and the phone number. keyExtractor is used to create keys for each element we render in this list, just like React needs in the web. Each key will be the ObjectID returned from MongoDB.
Finally, let's make sure our React Native application knows where to get those informations:
//I have only one component anyway...
componentWillMount(){
Meteor.connect('ws://localhost:3000/websocket')
}
We use the connect method from react-native-meteor.
Note: Because I am only using the iOS simulator here, I can use localhost. If you use the android simulator, you will need to use the IP address of your machine ( 192.168.xx.xx:3000/websocket for example).
Clicking on the Save Phone Number button will populate the database in our Meteor application. Our subscription to the publication will retrieve the informations and display them!
Just a final picture to show you how it looks on my iOS simulator:
Well, there you have it. You can now connect a React Native application to a Meteor application without a problem. Have fun!
Warning: It seems that using npm5 with create-react-native-app is buggy and doesn't work properly. You should probably use npm4 or yarn to make sure you don't encounter any problems for now.