Create a cross platform application with React native

 

First experience with react-native and react-native-web

To create a native app with code sharing today there are 2 main approaches:

    • Hybrid app: write in javascript, html and css, and the entire code is embedded and run in a web view in mobile. Like phonegap.
    • Js engine + native ui: write in javascript. Ui components are translated into native UI components. Other codes are run in a js engine provided by the mobile system.

React Native is a framework represented by the second philosophy. It lets you create a mobile app using Javascript. As a web app developer with not so much mobile background, it could be a good way to start a mobile app. React Native is based on React, same design as React, so he should have a good integration with other react lib. It is based on version 0.56.RC now, not yet a major version. But looking at who’s actually using React Native: Facebook, Youtube, Skype etc, we could have confidence in it. React Native is a Facebook project.

To make real code sharing, we expect to have at the same time a web app without re-writing the UI part. That comes with the “react-native-web” framework, who brings the Components and APIs of React Native to web. As mentioned in React Native Web home pages, it is used in production by Twitter Lite. It is also supported by react-scripts.

So let we start an experience of a cross device application with this two framework. I want to do something further than a hello world example. But let me start with initializing the project.

Initialize a project

There are two ways to initiate a React Native project as explained >here<

Create React Native App

A quick way to create and start a mobile app if you have a device on which you want to run (otherwise you will need to install an emulator).

npm install -g create-react-native-app
create-react-native-app AwesomeProject

It will be hosted by “expo” configuration so you can quickly run your native app within Expo client app.

Scripts run will deploy mobile app within an expo container.

React-native-cli

In this case you will need a full mobile development environment which means XCode for iOS and Android Studio and Android SDK for Android etc to start with.

npm install -g react-native-cli
react-native init MyNote

The script creates two folders additional to “Android” and “iOS” and initiate a default setting for native app without “expo”. This should be the best way for initiating a standard project.

To launch a simulator, take iOS for example, you can run

 react-native run-ios

Or you can also open .xcodeproj in XCode and run the project.

You can also do this job later in your react-native project with

react-native upgrade

Either the way of initialization, we now have a runnable native app project. So far so good. Everything goes well.

Configure the native project as a web app

React Native translates its UI components to native platform components for iOS and Android, and React-native-web will do the job for a web platform. Check its > Github page <

We will need to add a few things to make web app available :

      • On react-dom, react-native-web, babel-plugin-react-native-web>
      • A public folder with a index.html template
      • A entrypoint js for web index.web.js
      • And make a alias ‘react-native’ to ‘react-native-web’

In the entrypoint index.web.js, instead of the classic react way to render you application with the DOM, we will do this in the React Native way, using AppRegistry. So my entry point is something like this.

import App from './App';
import React from 'react';
import { AppRegistry } from 'react-native';

AppRegistry.registerComponent('MyNote', () => App);

AppRegistry.runApplication('MyNote', {
   initialProps: {},
   rootTag: document.getElementById('react-native-app')
});

The thing is, react-script can launch a react-native project and automatically do the magical alias to react-native-web, but the embedded webpack config required a specific folder structure that does not so much fit the structure created by react-native. So I create my  webpack.config.js and run a webpack dev server.

In the webpack config, we need a babel loader for everything expected to be compiled by Babel. And plug our “babel-plugin-react-native-web” here to take care of the aliases ‘react-native’ to ‘react-native-web’. Or you can also do this in you module export resolve.

And don‘t forget to set your entry index.web.js.

After all these, my project and my package.json look like this

My project & Package json

And I can now run my native app with xcode and on the other side my web app with script npm run web. When the code changes, a simple Cmd+R in simulator or in browser will reload app.

A little bit settings for the web part, it’s a pity that the web app initialization is not included by react-native init step. And now we are ready for our develop environment.

Developments : UI component and API

The development is very similar to classic react. Just using React Native component instead of DOM component.

The basic components of React Native are quite simple. View, Text, Image, TextInput, TouchableHighlight etc. You can easily associate a DOM interface using div, img, input, a with them. Most apps will end up using just these basic components.

Component style is defined by ‘style’ prop. If you are familiar with css, the style name and value match usually how it works on web.

The events and handlers are quite similar to DOM as well. For example a TextInput component has onChange, onKeyPress, onFocus and onBlur props.

For a web developer, you should be able to make it out quite well for this part.

More advanced native components are also available in react-native. Most common components are well supported in react-native-web. The latest version of react-native-web adds implement for SectionList.

Still there are platform specific components. DatePicker is one of them. We can regret that iOS and Android could not reach an agreement with DatePicker interface. React native provides a Platform API to make platform specific codes. For a DatePicker for example, we could have something like this :

 

const DatePicker = Platform.select({
   ios: <DatePickerIOS />,
   android: <DatePickerAndroid />,
   web: <input type='date' />
})

Many third party libraries exist today to unify the two mobiles platform codes (react-native-datepicker for example), but few of them includes web support.

Responsive

React-native component use FlexBox layout. FlexBox is a helpful tool to create responsive app. On the web side it will be translated into css flexbox properties, that means old browsers will not be supported, flexDirection, alignItems, justifyContent, alignSelf, flex properties are available in react-native, and work in the same way as in css.

Dimension is another helpful API. Dimension.get can give the current height and width. You can create a dynamic rendering and styling logic depending on it. The calculation should be done at every render to guarantee the dimensions up to date with any changing due to device rotation or browser resize. Dimension API provides a change event listener.

Platform API is also a choice to build rendering logic. In that case we usually would like to differentiate between a small mobile screen and a large browser window on laptop. Well actually Platform.OS and Platform.select has 3 possible values “iOS”, “Android” and “Web”. I don’t think it can distinguish an iPhone from a iPad, so your mobile screen layout may not be suitable for a tablet.

Navigation

Navigation is a hard part to make code sharing successful. Each platform has its own way to manage navigations and histories. Unfortunately it is also one of the essential part of app. React-native does not provide a “official” API pour navigation. It recommends some available navigation components. I’ve tried React Navigation which support both the mobile and web platform. Although, after trying several combination of react native and react navigation, I fixed in version 0.54.0 of react-native and 1.5.8 of react-navigation. Cause after react-navigation 2.0, web support is broken. And I had several problems to work react-navigation 1.5.8 with other versions of react-native. Live this instability in JS world. Well the fix for web is in V2 roadmap.

React Navigation provides basic features of navigation like navigate, history, routing. Advanced features that could be interesting in React Navigation :

      • Sub routing, multi-routing
      • Deep link in 3 platform
      • Customizable navigator
      • Provides customizable UI for navigation like header and tab.

Even though deep link is supported, I didn’t find any option to change url when path changed in web platform. That needs to be implemented manually.

Other classic features which do not need UI action works well in mobile device as in web browser, like async call, await, integration with Redux etc, as the code runs in a Javascript environment. If you use a JS library that does not reference DOM API, you should not have any surprise.

Conclusion

React native, with the help of React-native-web propose a quite simple way to create a cross device application.

      • It include the essential requirement of an application with a possibility to customize. It comes with a rich ecosystem around React.
      • It does not require a great mobile background to start and deploy a mobile app
      • It makes real code sharing between web and mobiles in 90% case.
      • UI development is very similar to html development
      • Ecosystem of react-native is very dynamic.
      • Compare with hybrid app, native component and api are used in react-native app (for mobile platforms).

There are still some drawbacks

      • To integrate web app with react-native, one will need some manual work.
      • Web is not always well supported by the third party libraries.

Even though, react-native + react-native-web is still a good choice to make a cross device app with a real code sharing and gains significantly in productivity.

 

Do you have questions? We would be happy to answer you!

CONTACT US!

Share
Zhe SUN
Zhe SUN

517

Leave a Reply

Your email address will not be published. Required fields are marked *