🐝

ExpoのDOM componentsでReact NativeにReact(Web)を組み込む

2024/08/21に公開

こんにちは!テラーノベルでiOS/Android/Webとフロントエンド周りを担当している @kazutoyoです!

先日、Expoチームが実験的な機能としてDOM componentsを公開しました。
今回はそちらについてまとめてみました。
https://docs.expo.dev/guides/dom-components/

DOM componentsって?

DOM componentsは、React(Web)でつくられたコンポーネントをWebViewとしてReact Native内に簡単に組み込むことができる仕組みです。

例えば、次のような dom-component.tsx コンポーネントのファイル上部に 'use dom' ディレクティブを記述します。

'use dom';

export default function DOMComponent({ name }: { name: string }) {
  return (
    <div>
      <h1>Hello, {name}</h1>
    </div>
  );
}

dom-component.tsx をReact Nativeのコンポーネントに追加することで、dom-component.tsxをWebViewを使って表示します。

import DOMComponent from './dom-component.tsx';

export default function App() {
  return (
    // This is a DOM component. It re-exports a wrapped `react-native-webview` behind the scenes.
    <DOMComponent name="Europa" />
  );
}

以下の動画ではshadcn/uiやMDXを使ったWeb用のページを、DOM componentsを使いReact Native上で表示しています。
https://x.com/Baconbrix/status/1824167778414366916

DOM componentsのメリット

既にReact(Web)で構築されたページがあり、Universal App化を検討しているとき

既にWebで作られたアプリケーションをExpoを使ってUniversal App[1]化しようと考えているとき、Native AppではDOM componentsを使って表示することができます。

パフォーマンスなどを考慮した場合、既にWebで実装された画面をReact Nativeでも同様に実装すべきですが、すべての画面を行うには多くのコストがかかります。
DOM Componentsを使ってWebViewで表示することで再実装の手間を減らし、段階的にUniversal App化を進めることが出来ます。

WebViewで表示するのが最適な画面のとき

MarkdownやHTMLで装飾されたコンテンツの表示、WebのCanvas APIを利用したい場合など、Nativeで実装するよりも最適な場面もあります。
そのようなときにDOM componentsを使うことで、通常のWebViewを使う場合と比べて以下のような開発体験を得ることが出来ます。

  • 高速リフレッシュとHot Module Replacement
  • オフラインをサポートしたページのエクスポート
  • 開発中のランタイムエラーのオーバーレイ
  • Native/Webの値の受け渡しをPropsで行える

Native/Webの値の受け渡し

PropsのインタフェースでNative↔Webで値を受け渡しできます。

次のようにDOM Componentでは hello: string を受け取ります。

'use dom';

export default function DOMComponent({ hello }: { hello: string }) {
  return <p>Hello, {hello}</p>;
}

Native側は次のようにDOM Componentに値を渡すことが出来ます。
Propsで指定できるのはシリアライズできる値(number / string / boolean / null / undefined / Array / Object)となっています。

import DOMComponent from './my-component';

export default function App() {
  return <DOMComponent hello={'world'} />;
}

また、DOM ComponentのPropsに関数を追加し、Nativeの機能の呼び出しや値の取得を行うことが出来ます。

DOM Component

'use dom';

export default function MyComponent({ hello }: { hello: (data: string) => Promise<void> }) {
  return <p onClick={() => hello('world')}>Click me</p>;
}

Native Component

import DomComponent from './my-component';

export default function App() {
  return (
    <DomComponent
      hello={(data: string) => {
        console.log('Hello', data);
      }}
    />
  );
}

このように、これまでWebViewで実装するよりも型安全にNativeとWebView内のコミュニケーションができます。

まとめ

このように、DOM componentsを使うことでReact Nativeに簡単にWebViewのページを追加することができます。
個人的にはWebViewで型安全にNativeとWebのコミュニケーションができるのが嬉しい機能でした。
まだ実験的な機能のためProductionで使うのが難しいですが、今後の開発に期待しています!

脚注
  1. ここでのUniversal Appとは、Expoチームが提唱しているReact Nativeを使いiOS/Android/Web…などといった多数のプラットフォームを対象とするアプリケーションです。 ↩︎

テラーノベル テックブログ

Discussion