ExpoのDOM componentsでReact NativeにReact(Web)を組み込む
こんにちは!テラーノベルでiOS/Android/Webとフロントエンド周りを担当している @kazutoyoです!
先日、Expoチームが実験的な機能として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上で表示しています。
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で使うのが難しいですが、今後の開発に期待しています!
-
ここでのUniversal Appとは、Expoチームが提唱しているReact Nativeを使いiOS/Android/Web…などといった多数のプラットフォームを対象とするアプリケーションです。 ↩︎
Discussion