React Native for Web
Using React and React Native in a single, shared codebase
If you’re building a react app that is intending to have mobile and web versions, react-native-web may be for you. Even if you’re not intending on using the shared components or styles, being able to share functionality (state management, fetch, etc) is a huge win for productivity and maintainability.
The github repo has a good overview on what react-native-web is, so I’ll leave that to the experts, but what I will give you are a few things I’ve learnt along the way that have helped me out.
I haven’t completely worked out the best way to get a project going. There are starter kits which, although I haven’t tried, look like the best way to get started.
With that said (and before knowing the above) I love
create-react-app so I ended up initialising a standard react repo with that, created another repo with
react-native init and then carefully merged them together with meld merge. It went fine and works, but took an hour or two to figure out, plus I later ejected to get access to the webpack config which lessens the advantages of using
create-react-app. In conclusion, I recommend going with a starter kit, although I suspect
create-react-app will full integrate into this at some stage (it’s latest release supports .web.js files).
Shared API Libraries
react-native-web provides a lot of shared components and apis, but there are a few that it doesn’t cover which other libraries do.
1. Storage: react-native-storage
Cross-platform storage is a bit tricky. The browser’s localStorage is synchronous but the mobile version of it, AsyncStorage, is as the name suggests… asynchronous. This means you can’t simply create a wrapper to use localStorage for web and AsyncStorage for the rest, because one returns the actual stored object and the other returns a promise. react-native-storage is great solution to this, it turns both into promises so you can call storage from anywhere and get a promise back. If you’re using redux and react-native-storage, then learn something like thunk as redux by default will yell at you if you try to do async actions with it.
2. Navigation: ReactNavigation
ReactNavigation is great for navigation on mobile, and also works on web. I couldn’t actually get it working on web, and only being able to use the routers and not the navigators is a bit of a drawback, so I’m waiting for some more documentation about it.
My interim solution was to use ReactNavigation for the mobile navigation and react-router for the web. This just means wrapping each app in its’ specific navigation library and writing a navigation utility that would use
navigator(screenName) on mobile and
browserHistory.push(screenName) on web. Works well, is simple and easy to setup, and is nicely abstracted away from the rest of the app.
One thing I noticed about ReactNative in general is that even if you have both the iOS and Android simulators up, only one will hot reload. I’m not sure if this is getting fixed but there’s a straightforward work around at the moment, which is running the react-native dev server on two ports (and pointing iOS at the second port you set up), here are the instructions. I originally thought having all three platforms hot reloading would be awesome for development, but I’ve found myself mostly only having one platform up at a time, or web + one mobile at best.
There is a use I have found for hot reloading all three platforms though, and that’s when you want to demo this system’s capability. You can talk about how productive this workflow is until you’re blue in the face, but simply changing a line of code and showing all three apps changing simultaneously gets your point across more succinctly.
2. Loading your dev environment
There can be a lot to set up each time you want to develop. Start up two servers, start up the iOS and android emulators, wait a minute for the android emulator to load then run react-native run-android. I recommend scripting the process. I used Alfred App.
So that’s my initial roundup. With this being a reasonably new and low documented library I was a little worried about spending a lot of time struggling against it to get things working. Whilst you need some experience in the react stack (including an understanding of webpack and babel), and will have to solve some problems without having a top quality walkthrough to reference, overall I’ve found this structure to be a pleasure to work with and unparalleled in output.
This is a new space and best practices and processes are still being figured out. Discussion and disagreement will be essential to pave the way to having strong resources in place that we can point to. If there’s any knowledge you want to share or parts you disagree with, I encourage you to get involved, and we can all figure this out together.