Rebuilding a website with react-native-web

Hyo
dooboolab
Published in
5 min readJan 19, 2021

I tried expo web in the previous post, and now I’ve tried pure react-native-web to re-implement our website dooboolab.com (the old website).

dooobolab.com (light mode)

Simply speaking, I had a great experience with building the web application using react-native. In addition, this is great that it has the potential to bring up the application to new platforms like iOS and android whenever we want to with minimal effort (some styles are not working identical so I had to fix it).

The work on bringing up web env to the react-native template has been made in a current pull request. The most important part to look into is how I’ve handled screens for app and web. I’ve provided wrapper utils as a HOC pattern to wrap screen components to fill the screen.

I might have a better workaround to handle the screen components but currently, this is the result. When using react-native-web, I’ve felt that this is not well compatible with the react-navigation header. For one example, as posted on Twitter, the back icon disappeared when navigating screens.

Also, the screen is pushed down by the size of the navigation header which resulted in a not perfectly fitted screen. This did not use to happen in expo-web which I feel Evan Bacon did more job with it.

However, most of the part, it felt reliable if I am not using native navigations like material-bottom-tab navigation and navigation header. Last time, I’ve suffered from a compile error in react-script using bottom-tab navigation, but don’t remember the actual error message.

Now, I want to share 3 main parts I’ve had in consideration in building web application with react-native.

1. Responsive

To cover responsive design, I’ve used react-responsive with styled-components. Below is how it looks.

function ThemeProvider({children, initialThemeType}: Props): ReactElement {
const isMobile = useMediaQuery({maxWidth: 767});
const isTablet = useMediaQuery({minWidth: 767, maxWidth: 992});
const isDesktop = useMediaQuery({minWidth: 992});
...

Then to support typescript, add styled.d.ts file.

import 'styled-components';
import type {Theme} from './utils/theme';
declare module 'styled-components' {
export interface DefaultTheme extends Theme {
isMobile?: boolean;
isTablet?: boolean;
isDesktop?: boolean;
}
}

Add them to theme props and pass them to ThemeProvider.

const theme: DefaultTheme = {...defaultTheme, ...media};

Now we are ready to use media query in styled-components almost similar to how we use to do in react web.

react version
react-native Version

Compare the react version and react-native version. The concept is similar.

The react version is somewhat simpler than the version in react-native. This is because the only props we can pass to original ThemeProvider in styled-component is theme prop. Hopefully, there can be a better approach in the future.

As a mobile-first design, in styled-component, when it comes to desktop screen size, we render the screen differently. Here is how it looks after that.

2. Dark Mode

The dark mode is also handled by styled-components. I’ve defined the theme variables like below.

Then added to the default theme in ThemeProvider after detecting the correct color scheme provided by Appearance in react-native.

Note that I’ve commented web to detect the dark mode. I’ve first thought that react-native might not care about web env but surprisingly, it also supported web.

Final result.

3. Utilities

Other important utilities to cover the correct web env along with natives are as follows.

  • Hoverable
    React Native by default doesn’t provide hoverable styles that should be supported in web. I’ve found the util and included it in the source code.
  • Linking
    In default, when you are navigating from the web and press the back button in the browser, it won’t go back to history. To support backing history, you should use linking provided by react-navigation.
Note that in the below code, I’ve had to provide linking only for the web, because, in mobile, it asked me to useLinking instead.
Final result
  • dotenv
    Previously, I used to use react-native-config for my env variables control. However, I found that this does not wonderfully take care on the web and I found react-native-dotenv which worked great on all 3 platforms.
For typescript user, you need to add global type declaration.
declare module '@env' {
export const apiKey: string;
export const appId: string;
export const authDomain: string;
export const databaseURL: string;
export const messagingSenderId: string;
export const projectId: string;
export const storageBucket: string;
}

I think that’s it. I’ve just summarized all the concepts and experience of building the app with react-native-web which hopefully helps many others starting react-native-web easily.

Also, look how great it looks in iOS either.

iOS app 👀

Lastly, I’d like to share an easy way to create react-native-web based react-native application with typescript.

1. Install dooboo-cli

yarn global add dooboo-cli// ornpm install -g dooboo-cli

2. Run dooboo init command and select [React Native App (typescript)]

3. Complete additional instruction and you are done.

Enjoy!

The full source code is here!

--

--