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).
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.
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 inweb
. 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.
- dotenv
Previously, I used to use react-native-config for myenv
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.
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.
Lastly, I’d like to share an easy way to create
react-native-web
basedreact-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.