Kumar Harsh Technical writer and software developer based in India.

Hands-on with React Native for Web: A complete tutorial

6 min read 1924

React Native Logo

One of the most important decisions to make when starting a new project is choosing your development stack. You need to select a platform on which most of your users are active, but at the same time, the platform shouldn’t be too restrictive.

The future growth of your application might require you to reach users on an entirely different platform. As such, your initial stack should be versatile enough to accommodate such growth requirements.

Speaking of versatile technologies, React Native for Web enables developers to use React Native Components and APIs on the web. This is a game-changer in the battle between mobile-first frameworks, as React Native is one of the most popular choices to build cross-platform mobile applications.

In this article, we will talk about the buzz around React Native for Web and set up a demo project with it, too!

What is React Native for Web?

React Native for Web enables developers to write a single React Native application that can run natively on Android and iOS, as well as on a web browser using standard web technologies. But considering that React, the conceptual parent of React Native, is built specifically for the web, it’s worth questioning why such a technology is necessary in the first place.

The reality is that the foundation of a mobile app is entirely different from the foundation of a web app. For instance, React uses basic HTML5 elements like div and span to construct its layout, while React Native uses custom UI APIs like View and Text. Due to this difference, very few technologies support building apps for both web and mobile.

React Native for Web is an attempt to bridge this gap. It is built to help create truly cross-platform applications using a single React Native codebase. But how does it do so? Let’s find out.

How does React Native for Web work?

As mentioned previously, web apps and mobile apps have very different foundations. There are distinct APIs in both platforms to do the same job, i.e., render UI.

The idea behind any framework that aims to bridge this inherent gap is simple: use one platform’s APIs to build the equivalent of the other platform’s APIs. React Native for Web does just that.

React Native for Web provides browser-compatible equivalents of React Native components. For example, if a <View> is used to render views in React Native mobile, a browser-compatible version of this <View> is available in React Native for Web, which has a method to compile this view down to a web <div>.

We made a custom demo for .
No really. Click here to check it out.

This raises an important point: not all native components can be made browser-friendly. Some mobile-oriented components make use of mobile hardware APIs, which are not directly accessible by a web browser.

This means we can’t use React Native for Web to completely port an app into its web version. But we can still port a major part of it, and more often than not, that is sufficient.

Styling is another area of difference between React and React Native. In React, we can use a long list of styling solutions, including CSS, Sass, CSS-in-JS, etc. In React Native, on the other hand, all styles are written in CSS-in-JS.

Perhaps unsurprisingly, React Native for Web adopts the CSS-in-JS approach of React Native, ensuring that the same set of styles work well in both mobile and web.

Building our own React Native for Web app

Now that we have a theoretical understanding of the concepts behind this addition to the React Native family of APIs, let’s go through the installation process to understand how to set up our web-friendly React Native application.

Getting started: Create a fresh app

First of all, we need to create a new React Native application:

react-native init WebTest

Running this command will create a new React Native project with the name WebTest. To test it out, run the following commands:

cd WebTest
react-native run-android # to try on an android device, OR
react-native run-ios # to try on an ios device

The above set of commands will run the sample project on the desired device. We should see a basic boilerplate page on the screen that says something similar to “Welcome to React Native!”

When we look into the project directory, it will contain two unique JavaScript files: index.android.js and index.ios.js. These files are specific to the respective platforms in their names. This means that if we edit the index.android.js file, we will notice the updates in the instance of the Android app. The same goes for the index.ios.js file.

These index files are the root entrypoint to our React Native application. We can create separate files and directories to house our components, but if they are to be used by the application, they will always be linked down directly/indirectly to these index files.

Now that we have a mobile-ready React Native application working, let’s enable it for the web!

Prepare the application for the web!

First off, we need to install the required dependencies via npm:

npm i react react-dom react-native-web

The above command installs react-native-web along with the original React package and react-dom into our project. This will be added to the list of dependencies present in package.json, which will contain a minimum of four dependencies: react, react-dom, react-native, and react-native-web.

Now that we have the main packages installed, we just need to do a few more things to make our application compatible with the web. We still haven’t addressed the difference between the two platforms yet. To make the React Native application compatible with web browsers, we need to use Babel and webpack in our project.

Babel helps compile ES6 JavaScript code into browser-compatible ES5 JavaScript code, and webpack bundles the compiled JavaScript code together for a faster development server and process.

The commands we need to run in order to fix these appropriately are:

npm i webpack babel-loader babel-preset-react babel-preset-es2015
npm i webpack-dev-server --save-dev

These will install the required Babel and webpack packages. With this, we’re done installing all the packages we’ll need. The next step involves configuring our project for the web.

Since we have installed the webpack package, we need to create a config file for it to provide it with the correct project details. This file will instruct the webpack package on how to build, bundle, and serve our code to the web clients. Apart from this, we will also provide an alias resolver, which will update the web version of our application with the correct imports.

Here’s how a typical webpack.config.js file would look:

const webpack = require('webpack');

module.exports = {
  entry: {
    main: './index.web.js',
  },
  module: {
    loaders: [
      {
        test: /\.js?$/,
        exclude: /node_modules/,
        loader: 'babel',
        query: {
          presets: ['es2015', 'react'],
        },
      },
    ],
  },
  resolve: {
    alias: {
      'react-native': 'react-native-web',
    },
  },
};

Note that this file has to be stored at the root of our project and not inside any directory. Also, notice the mention of index.web.js in this file, similar to the Android and iOS variants above. This makes sense given that webpack has been instructed to look for the web application inside this file, and we can define an alternate version of our app for the web if we want to.

Next off, let’s create the HTML skeleton for our web application. This will be a plain index.html file stored at the root of the project. We can customize this however we want, but note that these changes will be applied to all pages of the React Native application. Here’s what a sample index.html file would look like:

<!DOCTYPE html>
<html>
<head>
  <title>Testing on the Web!</title>
  <meta charSet="utf-8" />
  <meta content="initial-scale=1,width=device-width" name="viewport" />
</head>
<body>
  <div id="react-native-app"></div>
  <script type="text/javascript" src="/bundle.js"></script>
</body>
</html>

Now that we are done with all the boilerplate setup, we have one last thing to do. Remember we talked about an index.web.js file a little while back? Let’s build that:

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View
} from 'react-native';

class ReactNativeWeb extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          Welcome to React Native!
        </Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#142a3d',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
    color: '#ffffff',
  },
});

AppRegistry.registerComponent('ReactNativeWeb', () => ReactNativeWeb);
AppRegistry.runApplication('WebTest', { rootTag: document.getElementById('react-native-app') });

The only difference between an Android/iOS index and the web index file is in the last line. For the web, we need to instruct the loader to run the application inside the div tag that we just created in the index.html file. Without this, React Native will never know where to load and display the application.

This completes the setup for the web!

Test running on the web

Now that we have completed all the requirements for running a React Native application on the web, the next step would be testing it out. To do this, start webpack by running the following command:

./node_modules/.bin/webpack-dev-server -inline

This should start an instance of a webpack server in the terminal, and you should be able to view your React Native Web application at http://localhost:8080/!

At this point, you have a working, cross-platform application that supports Android, iOS, and the web. From here onwards, it is in your hands to take forth the development of the application.

Extending the sample React Native for Web app

Now that you have an application that supports the web as well, you can decide which path to take as you continue development. You have already seen the new index.web.js file that handles the web version of your React Native project. This makes it clear where you should look for issues if any arise.

As far as coding practices are concerned, you need to stick to inline and JSS styling methods since CSS is not supported in React Native applications. You also need to look out for some anomalies, like some unsupported libraries/APIs for all three platforms alike.

ListView is a great example of this because it is not supported by React Native for Web. This is totally normal and can be bypassed by using React Native’s ability to define platform-wise variants for any component.

While this lack of support for a number of APIs may compel you to reconsider building a web application on React Native, it is still among the easiest ways to build one codebase for iOS, Android, and the web.

Conclusion

Looking back at this tutorial, we discussed what React Native for Web is, the problem it solves, and how it works. We then set out to create our own React Native for Web application from scratch. We made a number of package installations and configuration tweaks before we could get a working version of our application on the web.

As you can infer from the last segment of this tutorial, React Native for Web is not yet totally ready for production. There are still quite a few unsupported APIs, which could rightfully make you question a move from React to React Native for Web. In the end, however, it depends upon your individual requirements.

Full visibility into production React apps

Debugging React applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

LogRocket is like a DVR for web apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your React apps — .

Kumar Harsh Technical writer and software developer based in India.

Leave a Reply