An easy way to integrate your React (or Preact) app into React Native app with WebView.
If you'd like to run your React web app in React Native, rewriting it for React Native or using react-native-web is preferred way in most cases. But sometimes rewriting is overkill, when you are just prototyping, or when the app includes something not available on React Native, like rich text editor with contenteditable or complicated logic with WebAssembly.
So how we run React app in React Native app as it is? It's logically possible if you run your web code in WebView using react-native-webview. However bundling React code with React Native is troublesome and implementing communication between React Native and WebView is so hard.
This library gives a bridge to make it easy. This will bundle the whole React app by some additional codes and it will be automatically re-compiled if you edit it. You rarely need to think which code you are editing for React or React Native, like isomorphic. The communication between React app and React Native app will be also simplified by this.
- Create React (or Preact) app bundle for WebView automatically in build process of React Native
.js,.ts,.jsx,.tsxand.mjswill be packed into one source.- NOTE: Only the edits in the entry file of web will invoke rebuild because of the limitation of metro's build process.
- Handle communication between React Native and WebView with React hook style
- With
useBridgehook, you can subscribe messages from WebView. - With
useSubscribehook, you can subscribe messages from React Native. emitfunction sends message.
- With
- Support bundling some assets in web side with ES6 import syntax
.jsonis imported as an object, like require in Node.js..txtand.mdare imported as string, like raw-loader..cssis injected to the HTML head of WebView, like css-loader..bmp,.gif,.png,.jpg,.jpeg,.webpand.svgare loaded as base64 encoded url, like url-loader..htmand.htmlare loaded as string, which can be rendered with React's dangerouslySetInnerHTML..wasmis imported like Node.js, which is compatible with ES Module Integration Proposal for WebAssembly.
If you have some feature requests or improvements, please create a issue or PR.
npm install react-native-react-bridge react-native-webview # Necessary only if you render React app in WebView npm install react-dom # Necessary only if you render Preact app in WebView npm install preact- react >= 16.8
- react-native >= 0.60
- (preact >= 10.0)
- Fix
metro.config.jsto use babelTransformer from this library.
module.exports = { transformer: { // This detects entry points of React app and transforms them // For the other files this will switch to use default `metro-react-native-babel-transformer` for transforming babelTransformerPath: require.resolve('react-native-react-bridge/lib/plugin'), ... }, rnrb: { // Set `true` if you use Preact in web side. // This will alias imports from `react` and `react-dom` to `preact/compat` automatically. preact: true }, ... };- Make entry file for web app.
- If you use React in web, import modules from
reactandreact-native-react-bridge/lib/web. - If you use Preact in web, import modules from
preactandreact-native-react-bridge/lib/web/preact. - If you use Preact in web but with React aliases, import modules from
reactandreact-native-react-bridge/lib/web.
// WebApp.js import React, { useState } from "react"; import { webViewRender, emit, useSubscribe, } from "react-native-react-bridge/lib/web"; // Importing css is supported import "./example.css"; // Images are loaded as base64 encoded string import image from "./foo.png"; const Root = () => { const [data, setData] = useState(""); // useSubscribe hook receives message from React Native useSubscribe((message) => { if (message.type === "success") { setData(message.data); } }); return ( <div> <img src={image} /> <div>{data}</div> <button onClick={() => { // emit sends message to React Native // type: event name // data: some data which will be serialized by JSON.stringify emit({ type: "hello", data: 123 }); }} /> </div> ); }; // This statement is detected by babelTransformer as an entry point // All dependencies are resolved, compressed and stringified into one file export default webViewRender(<Root />);- Use the entry file in your React Native app with WebView.
// App.js import React from "react"; import WebView from "react-native-webview"; import { useBridge } from "react-native-react-bridge"; import webApp from "./WebApp"; const App = () => { // useBridge hook create props for WebView and handle communication // 1st argument is the source code of React app // 2nd argument is callback to receive message from React const { ref, source, onMessage, emit } = useBridge(webApp, (message) => { // emit sends message to React // type: event name // data: some data which will be serialized by JSON.stringify if (message.type === "hello" && message.data === 123) { emit({ type: "success", data: "succeeded!" }); } }); return ( <WebView // ref, source and onMessage must be passed to react-native-webview ref={ref} source={source} onMessage={onMessage} /> ); };- Start your React Native app!
This repository includes demo app.
Before running this app, please prepare environment for React Native (https://reactnative.dev/docs/environment-setup).
git clone git@github.com:inokawa/react-native-react-bridge.git cd examples/DemoApp npm install npm run ios # or npm run android
