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:
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).
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.
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.
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
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
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.
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
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 :
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.
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 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.
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.