My Wild Introduction Into Hybrid Apps with React
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'),
});
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:
- 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 thereact-native
package. - Set the
main
inpackage.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! 📱
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>
);
}
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.
- SVGs are not working. I have no idea how to show an SVG file in a platform-agnostic way. See this issue on Github.
- Material design. I wanted to use React Native Paper because it looks amazing. They have a guide for setting it up for the web so I’ll give it a shot.
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!