This content originally appeared on DEV Community and was authored by Horus Lugo
I assume you're here because you want to know how to set up React Native Web in your Remix project. Well, you're lucky, I had to do this a few days ago, and I haven't run into trouble with it yet, so here's a tutorial about it:
Let's get started!
The result of this tutorial is also available as a GitHub repository that you can just clone to get started with your project: https://github.com/HorusGoul/remix-react-native-web-starter
1. Installing the react-native-web package
The first thing you have to do is install the react-native-web
package. However, since we can't customize our build process because Remix doesn't allow it yet, we'll need to use a package manager that will enable you to install a package with an alias. In this case, I decided to use pnpm
.
$ pnpm add react-native@npm:react-native-web
Then, the types if you're using TypeScript. Note that not all types will be correct for a React Native Web project, but that's out of the scope of this tutorial.
$ pnpm add --save-dev @types/react-native
2. React Native Web Styles
React Native Web has its own way of handling styles, and for SSR and hydration, they give you a stylesheet element that you have to place in the <head>
of your page.
We'll pass that stylesheet element to our Root using the Context API. Let's do that by creating a rn-styles.tsx
file inside the app
folder. Here's the content for that file:
import { createContext, Fragment, useContext } from "react";
export const ReactNativeStylesContext = createContext<
React.ReactElement<unknown>
>(<Fragment />);
export function useReactNativeStyles() {
return useContext(ReactNativeStylesContext);
}
Now, let's move to the app/root.tsx
file. We'll now use the useReactNativeStyles()
hook and put the stylesElement
inside the <head>
. Also, we'll wrap the <Outlet />
component with a View with a few properties to match the React Native Web behavior.
...
import { useReactNativeStyles } from "./rn-styles";
import { View, StyleSheet } from "react-native";
...
export default function App() {
const stylesElement = useReactNativeStyles();
return (
<html lang="en">
<head>
...
{stylesElement}
</head>
<body>
...
<View pointerEvents="box-none" style={styles.appContainer}>
<Outlet />
</View>
...
</body>
</html>
);
}
const styles = StyleSheet.create({
appContainer: {
flex: 1,
},
});
We also need to add a global stylesheet to Remix that contains the following.
html, body {
height: 100%;
}
body {
display: flex;
}
Take a look at the Remix Docs about Stylesheets if you don't know how to add CSS in a Remix project.
3. SSR and Hydration
Assuming you haven't modified the app/entry.client.tsx
file, just replace its contents with the following:
import { RemixBrowser } from "remix";
import { hydrate } from "react-dom";
import { AppRegistry } from "react-native";
import { ReactNativeStylesContext } from "./rn-styles";
const App = () => <RemixBrowser />;
AppRegistry.registerComponent("App", () => App);
// @ts-ignore
const { getStyleElement } = AppRegistry.getApplication("App");
hydrate(
<ReactNativeStylesContext.Provider value={getStyleElement()}>
<App />
</ReactNativeStylesContext.Provider>,
document
);
What's going on with that code? We're using React Native Web AppRegistry
to get the initial styles for the app and avoid hydration from failing.
Now, let's move to the app/entry.server.tsx
file, where we'll do a similar thing. Take a look at the code:
import { renderToString } from "react-dom/server";
import { RemixServer, type EntryContext } from "remix";
import { AppRegistry } from "react-native";
import { ReactNativeStylesContext } from "./rn-styles";
export default function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
const App = () => <RemixServer context={remixContext} url={request.url} />;
AppRegistry.registerComponent("App", () => App);
// @ts-ignore
const { getStyleElement } = AppRegistry.getApplication("App", {});
const page = (
<ReactNativeStylesContext.Provider value={getStyleElement()}>
<App />
</ReactNativeStylesContext.Provider>
);
const markup = renderToString(page);
responseHeaders.set("Content-Type", "text/html");
return new Response("<!DOCTYPE html>" + markup, {
status: responseStatusCode,
headers: responseHeaders,
});
}
Again, we're using the AppRegistry
to get the app styles and then pass them to the remix app using the ReactNativeStylesContext
.
4. Using React Native Web components
One last thing you could do if you're doing this in a new project is to go ahead and replace your app/routes/index.tsx
with the following:
import { Text, View } from "react-native";
export default function Index() {
return (
<View>
<Text>Hello, world!</Text>
</View>
);
}
Then do pnpm dev
and open your project in the browser to see your first Remix route rendered with React Native Web components!
I hope you liked this article! Don't forget to follow me on Twitter if you want to know when I publish something new about web development: @HorusGoul
This content originally appeared on DEV Community and was authored by Horus Lugo
Horus Lugo | Sciencx (2022-02-07T19:18:58+00:00) How to Setup React Native Web in a Remix project. Retrieved from https://www.scien.cx/2022/02/07/how-to-setup-react-native-web-in-a-remix-project/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.