Mobile
Article

Creating a Mobile Application with Reapp

By Jay Raj

This post was updated in May 2016 to reflect changes in React and Reapp.

React is a JavaScript library focused on building user interfaces. It’s increase in popularity has been helped in part by the fact that it’s created, used and maintained by Facebook.

Why React ?

React works on the concept of the “virtual DOM” which makes it different to other JS libraries. When a change occurs it updates the virtual DOM instead of updating the actual DOM. When there are changes in the virtual DOM, it makes a single update, avoiding frequent updates to DOM.

From the official site,

React abstracts away the DOM from you, giving a simpler programming model and better performance. React can also render on the server using Node, and it can power native apps using React Native.

Introducing Reapp.io

Reapp is a platform to create mobile apps. It provides a UI kit of components, optimized and customizable for creating mobile apps.

Reapp Demo

What You’ll Create

In this tutorial, you’ll learn how to create a mobile app using Reapp. The app will help a user save different locations, making use of the Google Maps API. It will use Firebase as a back end to save data.

Source code for this tutorial is available on GitHub.

Getting Started

Start by installing reapp and create a project called ReactApp.

npm install -g reapp
reapp new ReactApp

Open the project directory, run reapp and the app should be running at http://localhost:3010.

cd ReactApp && reapp run

Here is the resulting project structure.

ReactApp Project Structure

Inside the project directory is the app folder which contains the app.js file. The app.js file defines different routes for the application. The components folder contains the different components rendered when requesting a particular route.

Creating Views

Start by removing the sub.jsx file from the components/home folder. Open home.jsx and remove the existing code to start from scratch and understand how things work. You’ll create a react class called Home to render the component.

import { Reapp, React, View} from 'reapp-kit';

var Home = React.createClass({
  render: function() {
    return (
      <h1>Welcome to Reapp!!</h1>
    );
  }
});

export default Reapp(Home);

The render function returns the view to be displayed. Next update the routes in the app.js file.

import './theme';
import { router, route } from 'reapp-kit';

router(require,
  route('home', '/')
);

Save the changes and restart the server. Open http://localhost:3010 in your browser and you should see the default view. I recommend enabling device emulation in chrome developer tools to view the app as a mobile app.

Emulated device

Next you’ll integrate Google Maps into the view. Add a header for the app by modifying home.jsx to return a view inside the render function.

<View title="Where Am I">

</View>

Create a new map component to display Google maps by adding a google maps API reference to the assets/web/index.html page.

<script src="https://maps.googleapis.com/maps/api/js?v=3.exp"></script>

In home.jsx, create a new React component which will display the Google Map.

var MapView = React.createClass({

    render: function() {
        return (
            <div id="map"><span>Map Would be Here !!</span></div>
        );
    }
});

Add the MapView component to the home view.

<View title="Where Am I">
    <MapView />
</View>

Add the following style to assets/web/index.html.

<style>
#map {
  width: 100%;
  height: 400px;
  margin: 0px;
  padding: 0px;
}
</style>

Save changes and restart the server. You should see the text “Map Would be here !!” on your app screen.

Adding Google Maps

You have seen how to nest react components, so next you’ll remove the span inside the MapView render function and replace it with the actual map. Once the component has mounted it will create the Google Map and render it in the #map div.

You’ll write the Google Maps code in the componentWillMount lifecycle method. Inside the MapView component add the componentWillMount method.

componentDidMount: function() {
    // Code will be here
},

Inside componentDidMount define a default map location, map options and create the map.

var sitepoint = new google.maps.LatLng(-37.805723, 144.985360);

var mapOptions = {
        zoom: 3,
        center: sitepoint
    },
    map = new google.maps.Map(ReactDOM.findDOMNode(this), mapOptions);

   this.setState({
       map: map
   });

To use ReactDOM.findDOMNode you will need to require react-dom, so add this after the opening import statement.

var ReactDOM = require('react-dom')

In this code, ReactDOM.findDOMNode gets a reference to the component’s DOM node element and setState triggers UI updates. Save the changes and restart the server. If all is well, you should be able to view the map.

Map view displays

Now to add a marker to the Google Map. You’ll set several options to the marker such as animation and draggable.

marker = new google.maps.Marker({
     map:map,
     draggable:true,
     animation: google.maps.Animation.DROP,
     position: sitepoint
});

Here is the full MapView component:

var MapView = React.createClass({

    componentDidMount: function() {

      var sitepoint = new google.maps.LatLng(-37.805723, 144.985360);

      var mapOptions = {
              zoom: 3,
              center: sitepoint
          },
          map = new google.maps.Map(ReactDOM.findDOMNode(this), mapOptions);
          marker = new google.maps.Marker({
           map:map,
           draggable:true,
           animation: google.maps.Animation.DROP,
           position: sitepoint
      });

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

    render: function() {
        return (
            <div id="map"><span>Map Would be Here !!</span></div>
        );
    }
});

Save changes, restart the server and you should have a map with a marker.

Map with marker

Adding Position Info

When the user drags the marker the position info should show. To implement this, add the required HTML in the Home component. Change the render function code to look like this:

render: function() {
    return (
      <View title="Where Am I">

        <MapView />

        <div style={{width:100 + '%',height:100 + 'px',margin: 0 + ' auto',padding:10 + 'px'}} id="infoPanel">

            <div>
              <span><b>Position:</b></span>
              <span  id="info"></span>
            </div>

            <div>
              <span><b>Address:</b></span>
              <span  id="address"></span>
            </div>

        </div>
      </View>
    );
  }

Next you need to hard-code the default position (latitude and longitude) and address. Add this line after initializing the sitepoint variable in the componentDidMount method:

document.getElementById('info').innerHTML = '-37.805723, 144.985360';

To display the address you’ll use the Google Maps Geocoder.

geocoder.geocode({
    latLng: marker.getPosition()
}, function(responses) {
    if (responses && responses.length > 0) {
        document.getElementById('address').innerHTML = responses[0].formatted_address;
    }
});

Here is the current MapView component:

var MapView = React.createClass({

    componentDidMount: function() {

      var geocoder = new google.maps.Geocoder();
      var sitepoint = new google.maps.LatLng(-37.805723, 144.985360);

      document.getElementById('info').innerHTML = '-37.805723, 144.985360';



      var mapOptions = {
              zoom: 3,
              center: sitepoint
          },
          map = new google.maps.Map(ReactDOM.findDOMNode(this), mapOptions),
          marker = new google.maps.Marker({
           map:map,
           draggable:true,
           animation: google.maps.Animation.DROP,
           position: sitepoint
      });

      geocoder.geocode({
        latLng: marker.getPosition()
      }, function(responses) {
        if (responses && responses.length > 0) {
            document.getElementById('address').innerHTML = responses[0].formatted_address;
        }
      });

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

    render: function() {
        return (
            <div id="map"><span>Map Would be Here !!</span></div>
        );
    }
});

Save the changes, restart the server and you should have the default position and address displayed in the app.

Current App screenshot

Now add a dragend event listener to update the position and address once the marker is dragged. Inside the dragend callback function the marker position and address are fetched and the address and info elements updated with the values.

google.maps.event.addListener(marker, 'dragend', function(e) {

    var obj = marker.getPosition();
    document.getElementById('info').innerHTML = e.latLng;

    map.panTo(marker.getPosition());

    geocoder.geocode({
        latLng: obj
    }, function(responses) {

        if (responses && responses.length > 0) {
            document.getElementById('address').innerHTML = responses[0].formatted_address;
        }

    });
});

Save the changes and restart the server. Now when dragging the marker, the info updates when dragging ends.

Save Information to Firebase

Next add a button to save the coordinates to Firebase. First add reapp-ui to the project.

npm install reapp-ui@0.12.47

Import the button component into Home.jsx.

import Button from 'reapp-ui/components/Button';

Add the button to the Home component, at the bottom of the <View> component. On tapping the Save button a function will save the coordinates to Firebase.

<Button onTap={this.savePosition}>Save </Button>

Register for a free account with Firebase to use the service in this app. Once registered you should have a Firebase URL to use, here is my Firebase URL:

https://blistering-heat-2473.firebaseio.com

Login to your firebase account and click on the plus icon on the Firebase URL displayed in your dashboard to create a URL such as:

https://blistering-heat-2473.firebaseio.com/Position

And use this URL to save the location information.

Include a reference to Firebase in the assets/web/index.html page.

<script src="https://cdn.firebase.com/js/client/2.0.4/firebase.js"></script>

Next, define the savePosition function in the Home component, called when tapping the save button.

savePosition: function() {
    var wishRef = new Firebase('https://blistering-heat-2473.firebaseio.com/Position');
    var pos = document.getElementById('info').innerHTML;

    var address = document.getElementById('address').innerHTML;
    wishRef.push({
        'Position': pos,
        'Address': address
    });
},

This creates a Firebase object using the Firebase URL and pushes the data to Firebase using the push API function.

Save the changes and restart the server. Locate a position on the map and click save. Check firebase and the data should be saved.

Let’s add an alert to notify the user that the data has been saved. This wil use the modal component, so import modal into Home.jsx.

import Modal from 'reapp-ui/components/Modal';

Inside the Home View component’s render function, add the following modal code above <MapView />

{this.state.modal &&
          <Modal
            title="Coordinates Saved."
            onClose={() => this.setState({ modal: false })}>
          </Modal>
        }

This will be visible when the state.modal is true, so initialize state.modal to false when the app loads using the getInitialState method. Inside the Home component define the getInitialState.

getInitialState: function() {
    return {
      modal: false
    };
  }

Inside the savePosition method, after pushing the data to firebase, set the state.modal to true to show the modal.

this.setState({ modal: true });

Save the changes and restart the server. Once the app has loaded, click on the Save button to save the data and you should see the modal pop up.

Modal Popup

Conclusion

In this tutorial, you learnt how to create a mobile app using ReactJS, Reapp and Firebase. You created an app to save the map coordinates selected on a Google Map to Firebase.

I hope this tutorial serves as a good starting point for creating mobile apps using ReactJS. Let me know your thoughts and experiences using React and Reapp and how you think they compare to other mobile JavaScript frameworks.

  • Connor James Leech

    I’m having trouble adding the mapview. When I do I get a parse error:

    “`

    WARNING in ./app/app.js

    Critical dependencies:

    7:22-29 require function is used in a way, in which dependencies cannot be statically extracted

    @ ./app/app.js 7:22-29

    WARNING in ./app/components/Home.jsx

    Module parse failed: /usr/local/lib/node_modules/reapp/node_modules/reapp-pack/node_modules/react-hot-loader/index.js!/usr/local/lib/node_modules/reapp/node_modules/reapp-pack/node_modules/babel-loader/index.js?{“stage”: 0, “optional”: [“optimisation.react.constantElements”, “bluebirdCoroutines”]}!/Users/connorleech/Projects/reapp_maps/app/components/Home.jsx Line 14: Unexpected token <

    You may need an appropriate loader to handle this file type.

    | 'div',

    | { id: 'map' },

    | Map Would be Here !!

    | );

    |

    @ ./app ^./.*$

    webpack: bundle is now VALID.

    “`

    My code is very simple though:

    “`

    import { Reapp, React, View } from ‘reapp-kit’;

    var MapView = React.createClass({

    render: function(){

    return (

    Map Would be Here !!

    );

    }

    });

    var Home = React.createClass({

    render: function(){

    return (

    );

    }

    });

    export default Reapp(Home);

    “`

  • Connor James Leech

    can’t drag the marker even when I clone your repo

  • Chris Ward

    @connorjamesleech:disqus Are you still having trouble? I’m a little unclear as to where you were experiencing the problems? Reapp must have changed something the day we published this as it worked when I tested it!

  • Jenny Lee

    Thank you for the nice tutorial! Does reapp support isomorphic server-side rendering?

  • Dead Skunk

    Thanks for the tutorial, although it’s less a tutorial than “here are the steps to recreate our sample app”. Tutorials explain the what and why. What is componentWillMount? What is componentDidMount, how do I work with multiple views, etc. I can learn how to incorporate Google Maps and Firebase elsewhere, I came here to understand the architecture of a Reapp app. This got me started but that’s all.

    Also, there’s a typo. The instructions say “Inside the MapView component add the componentWillMount method.” and then the subsequent code snippet shows `componentDidMount`.

  • JoeyJGarcia

    I can’t even get the Welcome to Reapp page to work because of this error. I copied everything you provided for the Home.jsx and the app.js and removed the sub.jsx.

    .*$:9 Uncaught Error: Cannot find module ‘./[object Object]’.

    • Chris Ward

      Hmm, I also can’t get the github repo code to work anymore, I will see if we can get this updated.

  • Chris Ward

    Hi Matt, we updated this post (it was older) to fix some issues, but as far as I could see there were still commits to the project and it works. Yes, it is old tech, but i wanted to fix the issues raised from the comments below, some of which are fairly recent.

    Where did you see the news about it not being maintained?

  • daHolby

    It looks like this isn’t bringing in the Native Map or using the native map api. It’s the HTML version. So this is a hybrid solution right?

    • Chris Ward

      @daholby:disqus I’m not sure I completely understand the question, but yes, this is a hybrid app.

Recommended

Learn Coding Online
Learn Web Development

Start learning web development and design for free with SitePoint Premium!

Get the latest in Mobile, once a week, for free.