My Wild Introduction Into Hybrid Apps with React

Martin Džejky Jakubik
6 min readFeb 21, 2019

How I started and what I learned about react-native and react-native-web.

Let me give you a little background story. Recently, I have been reading a lot about React and React Native. I was very intrigued by the idea of writing native mobile apps using JSX (or TSX in my case). I mean — what the hell! I’ve never had a chance to create a mobile app. Let alone use web technologies to do it and learn React at the same time. 😱

I was ready. I was hooked! It was time to make a wild jump into the world of React and React Native. And hybrid apps. If you don’t know what hybrid apps are, here’s how I understand them:

Write an app in a single codebase and have it magically run both in the web browser and natively on a mobile device.

This is a combination of essentially creating a web app, PWA, and a native app in a single repository. And, apparently, React Native would allow me to do just that. ✨🌍📱

How I Started

In this post, I’ll be describing how I bootstrapped a new project and made it run both in the browser and natively. The app itself is primitive, without any logic. I wanted to get the configuration done first and make sure that the app runs in both environments. As already mentioned, I am using react-native with Expo and react-native-web. Let’s start with the web browser part.

Web Configuration First

How to start a new React project? Well, because I am using Angular CLI in all my Angular projects, naturally I stumbled upon create-react-app. I also learned that it supports react-native-web out of the box. 😍

create-react-app my-react-app

Then I added react-native-web and Typescript types.

yarn add react-native react-native-web @types/react @types/react-{dom,native,} typescript

Then, I changed the generated App component to a functional component and moved it to src/component/Root.tsx:

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

export default function Root() {
return (
<View>
<Text>Hello World</Text>
</View>
);
}

Notice that it is using the View and Text components imported from react-native and Typescript.

Finally, I changed the existing index.js file to index.web.js. The app needs to be initialized differently because of react-native-web so I replaced the file contents with this:

import { AppRegistry } from 'react-native';
import Root from './components/Root';

AppRegistry.registerComponent('Root', () => Root);
AppRegistry.runApplication('Root', {
rootTag: document.getElementById('root'),
});
Here’s the resulting web version of the app 🌍

Yay! 🎉 This was the easier part. Now, let’s look at the native configuration.

Native Configuration Second

I used Expo to manage the native side of the project (because who wouldn’t). The configuration was simple. I basically created a new app with expo init and then copied all necessary files and changes to my project.

Starting with the dependencies:

yarn add expo babel-preset-expo @types/expo

Also, I had to make these 2 changes in the package.json file:

  1. Set the react-native‘s package version to "react-native": "https://github.com/expo/react-native/archive/sdk-32.0.0.tar.gz". Expo requires its own version of the react-native package.
  2. Set the main in package.json to "main": "src/index.native.js". Expo is using this field to specify its entry point for the app.

Then I created the mentioned src/index.native.js file with these contents:

import { KeepAwake, registerRootComponent } from 'expo';
import Root from './components/Root';

if (__DEV__) {
KeepAwake.activate();
}

registerRootComponent(Root);

You probably guessed it already but the index.web.js file is used by react-scripts and the index.native.js file is used by Expo. This way you can have the same code used for both the web version and the native version.

Now by running expo start I can get the native version running on my phone! 📱

The app works, but the text is behind the status bar 📱

After all this progress, I had a hybrid app with a single codebase running both in the browser and natively on a mobile device. ✨🌍📱 That’s the magic I was talking about!

Now hold on. I still need to learn a ton of new things to work on this app. Things like Unstated, React lifecycle hooks, how to manage layout in React Native, even React Native itself! This is why I started the project after all 😎. I’ll be writing here on my Medium blog about everything new I learn while working on this project.

But, before I go, I wanted to tackle one more problem — navigation.

App Navigation

Every app needs a navigation system. What made things worse for me is that I have a hybrid application. At first, I tried my luck with React Navigation. However, this did not work in the browser for me. Luckily, it turned out that somebody had already solved this issue:

The only difference from my project is that I use Typescript. I added react-router-dom and react-router-native and created 2 files for routing:

  • src/routers/routing.ts for the web version:
export {
BrowserRouter as Router,
Switch,
Route,
Link
} from 'react-router-dom';
  • src/routers/routing.native.ts for the native version:
export {
NativeRouter as Router,
Switch,
Route,
Link,
} from 'react-router-native';

Then, I added the top-level router which imports from these routing files. The react-scripts and Expo make sure that the correct file is used for each platform. Here’s the gist of the router component:

import React from 'react';
import LoadingScreen from '../screens/LoadingScreen';
import LoginScreen from '../screens/LoginScreen';
import { Route, Router, Switch } from './routing';

export default function BaseRouter() {
return (
<Router>
<Switch>
<Route path="/" exact={true} component={LoadingScreen} />
<Route path="/login" component={LoginScreen} />
</Switch>
</Router>
);
}
Here’s how the application looks with simple navigation

That is as far as I got. I have a basic hybrid application set up for further development.

Next Steps and Questions

I will need to solve these problems next to continue working on the project.

Thank you for reading this article! ❤️ As said, I’ll continue working on this project and keep posting updates. Make sure to follow me if you are interested. I’m very new to React so my following articles will be on a beginner level.

If you like this article, make sure to smash that 👏👏👏 button! Wait, I think I already heard that line somewhere… Anyway, have a nice day!

--

--

Martin Džejky Jakubik

Frontend developer @ Exponea. Writing about things I learn along the way.