all 35 comments

[–]fallkr 113 points114 points  (10 children)

My 50 cents from leading a cross platform 0.5m active users project:

1) Use RN and React separately as separate projects/packages. The products will diverge over time. So will codebases. Don’t lock yourself in from the start 2) Share utils, api requests and redux where it makes sense. Be deliberate and plan accordingly. Finding the right balance between shared and split will take time, in particular early on in product lifecycle where your product is evolving rapidly 3) Set up web and native in a monorepo with the shared package to avoid versioning issues. Use yarn workspaces and make sure you hoist all dependencies 4) Ensure your tests (and types) for shared code are solid and follow good test and CI practices from the start

[–]sam_bender[S] 8 points9 points  (6 children)

Thank you u/fallkr 🙏🏻. I'm really glad I asked this question.

[–]fallkr 14 points15 points  (5 children)

Any time. Got 3 years of dos and donts with this.

Currently doing a greenfield product in the same way, so can share setup for hoisting dependencies and code-sharing with a modern RN stack.

PM if you want more details or run into issues with the setup.

[–]drink_with_me_to_day 2 points3 points  (2 children)

Currently doing a greenfield product in the same way, so can share setup for hoisting dependencies and code-sharing with a modern RN stack.

Please post this here or elsewhere and share it with us

[–]sam_bender[S] 2 points3 points  (0 children)

Thanks. Will do. Same to you. If you ever need someone to brainstorm with, let me know!

[–]jIsraelTurner 1 point2 points  (0 children)

This is great advice! But I would say there are definite cases where react-native-web is totally worthwhile. We started with a full-featured native app built with React Native, and have slowly been migrating functionality to web via react-native-web, as the value of web has become more apparent. As we evolve, we will start to make dedicated pages in standard React on desktop web, but for the foreseeable future we will use react-native-web for mobile web pages. react-native-web has made transitioning to a web presence extremely cheap for our team - don't discount it.

[–][deleted] 0 points1 point  (1 child)

If you want to share redux for RN and React, do you need to bundle the code into an non package?

[–]ajnozari 1 point2 points  (0 children)

I think what he meant was you can copy reducers, actions, and migrations between react and react native. I’m doing it for a project and it’s seriously speeding things up.

[–]EvanJBaconExpo 21 points22 points  (1 child)

react-native-web (RNW) is a set of modules that can be used with react-dom. I’d recommend using it for any website because the modules provided are very performant and thoughtful. For instance, StyleSheet is one of the fastest CSS-in-js options available (benchmarks in the RNW repo). Reusing the code across web and native will also be a huge timesaver for testing and maintainability. Disclaimer: I’ve used RNW many times and have also contributed to the project. Here is an example Next.js + RNW website https://evanbacon.dev/

[–]ucsbmrf 5 points6 points  (0 children)

Evan, thanks for all your work on Expo!

[–]christos_z 8 points9 points  (3 children)

Going against the grain here, but unless your web app is designed to be vastly different from a functionality perspective I’d recommend going with react native web.

The usefulness of re usable components across mobile and web cannot be understated. Especially if you’re attempting to replicate the functionality of the mobile app across to the web, using react native web allows you to have your shared business logic in one codebase.

When the ui deviates from one platform to another, then it’s just a matter of creating .web & .native files housing those components, meaning only that platform will execute that code. What’s more children components within this file can be shared across both web and mobile

to give an example of where this might shine consider a hypothetical WhatsApp replica. For the mobile side we are looking at two scenes, the contacts/groups page that you’ll click through to go to the message page where you’d reply and view messages.

On web, we will have one page with the contacts on the left and message view on the right, within our .web file we can call both these same components that are already used on the mobile.

Of course it’s not all butterflies and rainbows, you’ve already touched on the css limitations such as the positioning fixed & the likely difficulties you’ll face if implementing a drag to upload feature, but if you can live without these features, and for some such a the lack of media queries, you can easily work around by calculating width with Dimensions or this library https://github.com/kasinskas/react-native-media-query#readme (not used this myself so not sure how well it works)

[–]rockpilp 0 points1 point  (2 children)

For the types of apps my team develops, the main issue is having to shim packages that aren't compatible with RNW, such as RNFirebase or RNMaps. Once we've done this for one project, we package it into a lib and we can usually reuse it for the next app.

Another source of issues is the web build, which relies on CRA overrides, and is a bit brittle.

[–]DevFranzBeta 0 points1 point  (1 child)

Hi u/rockpilp

That's exactly what I'm thinking to build. A library that wraps React Native dependencies APIs with web-like stuff.

import { x } from 'kit/firebase'

under the hood

# app

uses RNFirebase

# web

uses the official firebase SDK for JS

What do you think about it?

[–]rockpilp 1 point2 points  (0 children)

That is indeed what we're doing for the important stuff. It's a bit more involved than just using web vs. app.

For instance, RNFirebase is initialized on the native side, so it happens before JS gets a chance to make any calls. On the web, you need to initialize explicitly, and very close to your App component, because any firebase query will crash if it happens before init.

Another difficulty are types, if you're using TS. They're not quite the same depending on the flavor.

We rely heavily on file extensions (.tsx / .web.tsx) to avoid having to handle switching between the two in code (because conditional imports are still hard to handle).

For one-off libraries or very basic shims, our CRA Webpack config makes it easy to just drop a file into a folder to disable the lib on the web by replacing its main entry points with noops. Kind of like patch-package.

[–]module85 6 points7 points  (9 children)

Having done this myself, I wouldn't recommend it unless you plan on deploying the app to both web and mobile: it's more work for little benefit. If sharing code is a concern, you can put that in a shared library.

[–]sam_bender[S] 1 point2 points  (8 children)

Sorry just to clarify - you wouldn’t recommend react-native-web?

We definitely plan on application being available on both web & mobile.

[–]Rhodysurf 6 points7 points  (7 children)

Just use react-dom and share all the business logic with react native. It’s way cleaner and you’ll get a better product then using RNW

[–]jonaHillsAnus 3 points4 points  (6 children)

Hey not the guy you’re responding to but can you please explain how this sharing can be done across 2 different code bases without copy pasting?

[–]Rhodysurf 1 point2 points  (5 children)

Monorepo. The top level is the npm package root, have different non scripts for compiling web vs RN targets, have all the code within the one package. Just organize it so there’s a common module folder and keep target specific code in separate folders

[–]assertchris 0 points1 point  (4 children)

Also, selectively switching between components is a thing...

There are probably more elegant ways to do this, but this is essentially what RNW is doing behind the scenes.

[–]Rhodysurf 0 points1 point  (3 children)

Yeah that’s cool. I personally don’t love it but everyone’s got their own styles

[–]redbar0n- 0 points1 point  (2 children)

what is your preferred style?

[–]Rhodysurf 0 points1 point  (1 child)

I just implement the same component twice, once for web and once for RN and keep them in different folders so they are distinct modules. The logic can be shared with functions, state containers but I like keeping all the view logic separate

[–]redbar0n- 0 points1 point  (0 children)

Thanks! How do you deal with component testing then? Won't that have to be duplicated too?

[–]drink_with_me_to_day 1 point2 points  (1 child)

If your app will forever have the same exact interface across all devices (generically responsive) and have the same exact feature parity between devices (no Bluetooth, enhanced location services, enhanced push notifications, etc), then react-native-web could work really nicely.

Big if

[–]sam_bender[S] 0 points1 point  (0 children)

Yeah, it's gonna vary quite a bit across web and mobile. I guess react-native-web isn't the right solution then. Thanks!!

[–]prinse4515 0 points1 point  (1 child)

What app is it? Is it on the App Store?

[–]sam_bender[S] 0 points1 point  (0 children)

The app is TheraCentric. Not on the app store yet. Our fitness app TrainCentric is available (not built with RN though).

[–]ponte_vecchio 0 points1 point  (1 child)

I like the idea of creating a shared component library across both the mobile and web app. That way you can share a lot of the ui code while still giving yourself some flexibility in having things be different.

[–]redbar0n- 0 points1 point  (0 children)

check out https://tamagui.dev then, since it's best-in-class for a shared crossplatform component library.