React Native + GraphQL -> Part 2

In the part 1, I’ve talked about the basics fundamentals of using GraphQL with React Native. For this last article, I’m going to introduce to you how implement queries and mutations in RN.

Ok, get started. First that all, you have to modify the following components:

components/Post.js:

import React, { Component } from 'react';
import { View, Image, Text, StyleSheet } from 'react-native'
class Post extends Component {
  state = {
   width: 0,
   height: 0,
  }
 componentDidMount() {
   Image.getSize(this.props.imageUrl, (width, height) => {
   const imageHeight = 250
   const scaleFactor = height / imageHeight
   const imageWidth = width / scaleFactor
   this.setState({ width: imageWidth, height: imageHeight })
 })
}
render() {
 const { width, height } = this.state
 return (
  <View>
   <View style={styles.imageContainer}>
    <Image source={{ uri: this.props.imageUrl }}
     style={{ width, height }}
     resizeMode='contain'
/>
 </View>
 <Text style={styles.title}>
   {this.props.description}
 </Text>
</View>
)}}
const styles = StyleSheet.create({
 imageContainer: {
  justifyContent: 'center',
  alignItems: 'center',
  backgroundColor: 'rgba(0,0,0,.07)'
 },
 title: {
  padding: 22,
  color: 'rgba(0,0,0,.8)',
  fontWeight: '300',
  fontSize: 16,
 },
})
export default Post;

components/ListPage.js:

import React, { Component } from 'react';
import Post from './Post';
import {View,TouchableHighlight,ListView,Modal,StyleSheet,Text} from 'react-native';
class ListPage extends Component {
 constructor(props) {
super(props)
const ds = new ListView.DataSource({ rowHasChanged:
(r1, r2) => r1 !== r2 })
   this.state = {
dataSource: ds.cloneWithRows([]),
modalVisible: false,
}
}
 render() {
  return (
   <View style={styles.container}>
    <ListView enableEmptySections={true} 
dataSource= . {this.state.dataSource}
renderRow={(post) =>
(<Post description={post.description}
imageUrl= {post.imageUrl}/>)}/>
</View>
);
 }
}
const styles = StyleSheet.create({
 container: {
  flex: 1,
  paddingTop: 22
 },
 createPostButtonContainer: {
  justifyContent: 'center',
  alignItems: 'center',
 },
 createPostButton: {
  backgroundColor: 'rgba(39,174,96,1)',
  color: 'white',
  textAlign: 'center',
  fontSize: 22,
  height: 60,
  width: 480,
  paddingTop: 18,
 }
})
export default ListPage;

Now we should go to App.js and implement the following code:

import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import ListPage from './components/ListPage';
import { ApolloProvider, createNetworkInterface, ApolloClient } from 'react-apollo'
const networkInterface = createNetworkInterface({ uri: 'https://api.graph.cool/simple/v1/cj540mfdej4s30175x464453g' })
const client = new ApolloClient({ networkInterface })
export default class App extends React.Component {
 render() {
  return (
   <ApolloProvider client={client}>
    <ListPage />
   </ApolloProvider>
  );
 }
}
const styles = StyleSheet.create({
 container: {
  flex: 1,
  backgroundColor: '#fff',
  alignItems: 'center',
  justifyContent: 'center',
 },
});

I’ve created a new instance of ApolloClient. The uri that I have to pass to the createNetworkInterface call is the GraphQL endpoint for the Simple API that I generated in the first article using graphcool init. You can also retrieve that endpoint from the Graphcool console by selecting your project and then clicking the ENDPOINTS-button in the bottom-left corner.

Note that the ApolloProvider is wrapping to ListPage, which enables all child components to access the functionality from Apollo Client to send queries and mutations.

How can I implement the queries and mutations?

Now we are ready to use Apollo in our components to interact with the GraphQL API!

Querying all Posts in ListPage

To display all posts in ListPage, we're adding three new imports in components/ListPage.js

import { graphql, gql } from 'react-apollo';

Apart from the Post component that renders a single post, we import gql and graphql. gql is used to create queries and mutations. graphql actually is a higher-order component that takes as input arguments one or more queries and/or mutations that were created with gql as well as a React component and injects the data from the query and/or the mutation function into the component as a prop.

Above of the class definition of ListPage, we’ll add the allPosts query:

We’re sorting the posts in descending order, so the latest posts appear on top of the list.

We need to be secure that the list is filled so I’ll use the React’s componentWillReceiveProps method for verifying that the Graphql’s query is getting the post correctly. You should insert the following snippet below of the constructor class:

I’m first checking if the data has already been loaded with this.props.data.loading. If loading is set to false, the data has arrived and we can map over this.props.data.allPosts to display the posts.

Next, you have to add on the first line of the render:

With the snippet before, we’re going to show a Text that tell us the status of the query, in other words, if the query was loaded or not.

The PostList needs to use the query result, for that, we’ll use the graphql component for passing the query result like a prop to the PostList:

Creating Posts in CreatePage

Adding mutations to React components is similar to adding queries, but instead of injected data, functions are injected for each mutation.

I’ve changed this component, please use the following snippet:

class CreatePage extends Component {
 constructor(props) {
  super(props)
  this.state = {
   description: '',
   imageUrl: '',
  }
}
 render() {
  return (
   <View style={styles.container}>
    <View style={styles.addImageContainer}>
     <View style={styles.addImage}>
      <View style={styles.photoPlaceholderContainer}>
      {
       this.state.imageUrl.length > 0 ?
       <Image source={{ uri: this.state.imageUrl }}
       style={{ height: 80, width: 80 }} resizeMode='contain' />
       :
       <View style={styles.photoPlaceholder} /> }
      </View>
      <TextInput style={styles.imageUrlInput}
       placeholder='Paste your image URL here...'
       onChangeText={(text) => this.setState({ imageUrl: text })}
       value={this.state.imageUrl}     
placeholderTextColor='rgba(42,126,211,.5)'/>
   </View>
  </View>
 <TextInput style={styles.descriptionInput}
   placeholder='Type a description...'
   onChangeText={(text) => this.setState({ description: text })}
   value={this.state.description}
 />
 <View style={styles.buttons}>
  <TouchableHighlight
  style={styles.cancelButton}
  onPress={() => this.props.onComplete()}>
   <Text style={styles.cancelButtonText}>Cancel</Text>
</TouchableHighlight>
  <TouchableHighlight
   style={styles.saveButton}
   onPress={() => this._createPost()} >
    <Text style={styles.saveButtonText}>Create Post</Text>
  </TouchableHighlight>
 </View>
</View>
);}
_createPost = async () => {
 const { description, imageUrl } = this.state
 await this.props.createPostMutation({
 variables: { description, imageUrl }
})
this.props.onComplete()
}}

Apollo related packages at the top of components/CreatePage.js:

Ok, before the class definition of CreatePage , you have adding the mutation that create posts:

The same way that ListPage component, you HAVE to pass the mutation as a prop to the component:

export default graphql(createPostMutation, { name: 'createPostMutation' })(CreatePage);

Ok, if you made all steps in this tutorial, you’re ready for testing the app, run the command npm run ios or npm run android , but before opening any simulator IOS/Android, React Native will install the app on your simulator. Other option is to install the app within a real device, for that RN prints in the console a QR that you can use:

Install the Expo app within your real device, this app is free and available for IOS/Android OS. Then, opening the Expo app and scan the QR that RN has created, MAGIC, the app that we’ve created will be installed on your device.

Ok, don’t matter if you installed the app on the simulator or real device, it should looks like:

Conclusion

That’s it! Using create-react-app and Apollo Client, it's easy to write React applications that work with a GraphQL backend. If you want to dive deeper in the example code, you can check it out on GitHub.

Thank you for reading, keep being a NINJA.