Today I’ll share a little bit of the knowledge I gained through one of Innovative Research Technologies' projects and teach you to get up and running with this toolset.
PS: This article assumes you have a React Native environment setup. In case you don't, check out Setting up the development environment on React Native's docs
Why You Should be Interested in React Native Web
On the 21st of October 2021, Fernando Rojo Talked about how he created his company, Beatgig, and how the company was able to scale to 10 million dollars in revenue thanks in large part to its app, which was built in record time and with full feature parity between platforms, by a single engineer, Fernando himself. The speaker went ahead and revealed the secret which allowed him to build his company’s app with such agility:
a combination of a previously existent tool React Native Web, which makes it possible to create React and React Native applications with a single code base, combined with a pantheon of new tools created by Fernando itself with the intent of using these powerful tools alongside the power of Next.JS, while also making the experience of developing mobile and web applications in the same codebase as pleasant as possible.
Beatgig's success story, plus all the tools created to make that success possible, got a lot of attention from the community. Amongst the interested, was one of G2I’s clients, Innovative Research Technologies (formerly part of Quest Mindshare), which has assembled a team of developers to write an app using these technologies.
I was selected to be a part of that team, and in the last couple of months, my team and I dedicated ourselves to mastering this stack, while building our application, which is currently in production.
During that time, I learned a lot about the stack and even merged a PR into the Solito (one of the tools created by Fernando for this stack)
So, today I’ll share a little bit of the knowledge I gained during this project and teach you to get up and running with this toolset.
The fastest way to get started is to clone Solito’s Starter Project or bootstrap an application using create-solito-app, a CLI created to save us the headache of having to manually configure a new Solito project.
“Wait, what is Solito ? I’ve never heard of that” — (probably) You
Solito is one of the tools that form this stack. It’s a package that aims unify the navigation API for both Next.JS and React Native applications. We’ll talk more about it in a couple minutes.
Creating the Application
We’re going to use create-solito-app to bootstrap our application. Assuming you have Node.JS installed, all you need to do is type the following command into your terminal
and hit enter. Then Solito’s CLI will guide you through the project’s creation.
Understanding the Project’s Structure
The two folders that matter for us are apps and packages. Let's understand them:
The apps folder is where our native applications exist. We’ll use it to configure web and mobile native-specific behavior and create Next.JS routes
The Packages folder is where we’ll spend the majority of our time coding.
It’s meant to contain the cross platform code of our application. Let’s understand what should go inside each of the folders listed under packages/app:
- features: Each feature represents one of our application’s routes.
- navigation: Inside this folder lives the native navigation configuration.
- provider: Under this folder we have the common provider for our apps. Inside this folder we have all the providers that’ll be used in our application. Theme providers, state management library’s configs and so on will be placed here
These default folders will not be enough for us to build an entire project. In a few moments we will create new structures inside this folder to accommodate the needs of our demo project
Running the Project
Now that we roughly understand the project’s structure. Let’s learn how to run it.
Since this app is both a web and a mobile one, we have a couple of options for how to run it
Running the Web Project
To run the Next.JS project, simply type:
on your terminal, and then type enter. after that, You just need to wait a couple seconds, and your project will be running on http://localhost:3000/
Running the Mobile Project
Running the mobile project is as easy as running the web one. Inside your terminal, type:
After that, you will be able to choose whether you want to run the project on an Android device or on an iOS emulator.
Analyzing the App
Since the intent of this app is to serve as an initial template, it is as simple as possible. It only has two routes. The initial:
and /user/[user_id], which can be accessed by clicking on either of the two links shown on the screen:
One of Solito’s main goals is making url params easily accesible in both sides of our cross platform stack. This screen serves the purpose of showing how easy it is to do that in Solito. If you’re running your project on web, you can change the last portion of the URL and see the User ID on your UI changing.
Talking about navigation is a good hook for me to start teaching you about the 3 fundamental concepts for building cross-platform applications with Solito, since navigation is one of them.
The Three Fundamental Concepts
In my opinion, there are three fundamental concepts, without which it is impossible to build a good cross-platform application.
- Platform Specific Code
Let’s go through each one of them.
Navigation is a vital part of any application, and it was an especially challenging part of building cross-platform applications, since not only were the navigation APIs completely different between the mobile part and the web part of the application, but the very way in which the route rendering is completely different between platforms.
Solito was created to solve those problems. According to its own docs, Solito is:
1 — A tiny wrapper around React Navigation and Next.js that lets you share navigation code across platforms. 2 — A set of patterns and examples for building cross-platform apps with React Native + Next.js.
2 — A set of patterns and examples for building cross-platform apps with React Native + Next.js.
1 — Navigation
Before navigating between routes, we need to know how to create one. So let’s cover that first.
1.1 — Creating a route
As mentioned before, our application will live under the packages folder. We want to create a new route, and route components are placed inside packages/apps/features.
So inside features, create a new folder called new-page. Inside your newly created folder, create a file called NewPage.tsx. Let's make that component as simple as possible for now.
react-native-web uses react-native synthax, and the transpiles that code into web code, so we’ll be writing react native components throughout this app. To get started you can copy the following code snippet:
Now that we have created our first feature, it’s time to make it available in our Next and expo applications
1.1.1 — Creating Next.JS routes
Next.JS routes are created inside the apps folder. Creating a Next.JS route in a Solito application follows the page creation script in a standard next application.
We just need to navigate to apps/next/pages and create our new route there, as component. So, inside the pages folder, let's create a file called new-page.tsx. This component will simply import NewPage.tsx from packages/app/features. Your component should look like this:
and your folder structure inside apps/next/pages should look like this:
Once this is done, our page will be successfully created and will be accessible on http://localhost:3000/new-page.
1.1.2 — Creating expo routes
Creating an expo route is multi step process, but still, a very simple one. The first step must be executed inside packages/app/navigation/native/index.tsx. Once you open that file, you’ll find the following content:
If you’re familiar with React Navigation this code should look pretty straightforward. Basically, each Stack.Screen represents one of your application's routes.
So in order for us to create a new route, we need to add a new Stack.Screen. The two required fields for a new screen are name and component.
The screen name must be the same name we gave our Next.JS route. And the component prop will receive the component we created inside features.
After adding the new Stack.Screen, your file will look like this:
To map a URL to a screen on the native app, we’ll use React Navigation’s linking feature. To do so, open packages/app/provider/navigation/index.tsx, and inside the config object, add our screen: new-page. After that your code should look like this:
1.2 — Navigating between routes
Now that our new route is in place, we need a way to access it (without having to manually change the browser’s URL). The two most common ways of navigating between routes using Solito are either by using the the Link component (and its variations) and using the useRouter hook.
We are going to use the Link component, so we can go from the home screen to the new-page route. Achieving this is very simple. We just need to edit the home page component. To do so, we must navigate to packages/app/features/home/screen.tsx, and replace the existing TextLink's href, so it takes us to a new route.
Search for the following code snippet:
and change its href property, so it’ll take us to our desired page, new-page
Now, by clicking our link, we’ll navigate to our new page, in all of our platforms.
2 — Responsiveness
Now that we’re able to navigate between our routes, it’s time to start adding content to them, and we’ll need that content to look different on different screen resolutions. That’s easy to do, thanks to Dripsy Another one of Fernandos’s projects, which is built to ease the task of creating responsive designs for this stack.
There are three main ways of handling with responsiveness using this stack, and they are:
2.1 — inline styles
One way you can style your components using dripsy, is by importing dripsy’s components instead of the React Native ones. They’ll behave exactly the same, except for the fact that dripsy components can receive a sx prop.
This prop behaves just like the styles one, except for a couple differences, the main one being the fact that it is can receive arrays as style values, and each array value will be used in a certain resolution. By default, dripsy works with 4 breakpoints (meaning you can pass styles for 4 different resolutions).
Let’s edit our new page component so we can understand this a little bit better. Instead of importing Text and View from react-native, let's import them from dripsy. Let’s also rename the style property from our View to sx.
Last but not least, let’s add a background color to our View's sx object. Instead of assigning it a single, value, assing it an array of values with whatever colors you like the most.
Each of the values will be displayed at a different resolution. Leftmost values are displayed at lower resolutions, while rightmost values are displayed at higher resolutions. The exact resolutions at which each value is displayed are:
For our specific case that means that every time our screen resolution is smaller than 577 pixels, our background color will be red. Every time it’s between 576 and 768 it’ll be white, and so on. Your final component should look like this:
To see the different styles in action, we just need to resize our browser’s screen and watch the changes happen.
The other way of creating responsive styles using dripsy is by using styled.
2.2 — using styled
According to Dripsy’s docs on styled, it’s a way of turning react-native components into Drispy ones.
But for me, its greatest power is its similarity to Styled Components. I highly recommend you check out their docs.
2.3 — useResponsiveValue
Sometimes you want to return completely different layouts depending on the screen’s resolution. In those types of situations, useResponsiveValue will do the trick.
That hook can be imported from Dripsy and it expects an array of values, that follow the exact same logic as the styles. It’ll return each one of the available array values
This hook is a very simple one to use, here’s an example:
In this example, I’m returning strings, but you can return whatever you want from that hook. The way I used this hook the most is to choose which layout I should render according to the resolution.
3 — Platform Specific Code
Last but not least, let’s talk about platform-specific code. Sometimes you will need to have very different implementations depending on the platform the app is running on.
And that’s also really easy to handle. You just need to add .[platform] before the file extension. For instance, let's say we have a component called PlatformIcon.tsx, and we want to have a different return for each platform, one approach to solving this would be splitting PlatformIcon.tsx into:
And when we were to import it, we would just use the following line of code:
and that code would behave differently in each platform.
You can also have platform specific code for one platform, and then the file without a platform identificator will be the fallback. So if we had
the PlatformIcon component would have a specific behavior for the web, while android and IOS would fallback to our default component ( PlatformIcon.tsx)
Done with the basics
Now that we’re done with the basic concepts of using this stack, go ahead and build something with it and experience its power by yourself.