0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Svelte でコンポーネントを作り React で糊付けする(ペライチ React で Snippet 編)

Last updated at Posted at 2025-05-14

はじめに

前々回前回 と、実用性とは程遠いコードを示して自己満足していましたが、今回も引き続き自己満足に浸りたいと思います(ついてきてくれる人だけついてきてくれていればそれで満足ですから!😭)。

Svelte には Snippet なるものがあるらしく、これを使えば React でいうところの Render prop 的なものが実現できます。

ペライチ React なサンプルコードを示し、前回と違う部分だけ解説します。

サンプルコード

index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="initial-scale=1, width=device-width" />
  </head>
  <body>
    <div id="app"></div>

    <script type="importmap">
      {
        "imports": {
          "svelte/": "https://esm.sh/svelte@5/"
        }
      }
    </script>

    <script type="module">

import React from "https://esm.sh/react@19?dev";
import ReactDOM from "https://esm.sh/react-dom@19?dev";
import ReactDOMClient from "https://esm.sh/react-dom@19/client?dev";

import {VERSION, compile} from 'svelte/compiler';
import {mount, unmount, createRawSnippet} from 'svelte/';

//
const sv = compile(`
  <script>
    const {name = 'world', content} = $props();
  <\/script>   <!-- ペライチの場合、\ を付けないと script タグの閉じと誤認識されてしまう? -->

  <h1>Hello {name}!</h1>
  <div>
    {@render content?.()}
  </div>

  <style>
    h1 {
      color: red;
    }
  </style>
`, {/*css: 'injected'*/});

console.log(sv.js.code, sv.css.code);

//
const App = props => {

  const refDiv = React.useRef();

  React.useEffect(() => {
    const controller = new AbortController();

    (async() => {
      const SVC = await import(`data:text/javascript,${sv.js.code}`);
      const cssModule = await import(`data:text/css,${sv.css.code}`, {with: {type: 'css'}});
  
      document.adoptedStyleSheets = [...document.adoptedStyleSheets, cssModule.default];
  
      const content = createRawSnippet(() => ({
        render: () => `<p>Which do you like React or Svelte?</p>`,
      }));

      const svc = mount(SVC.default, {target: refDiv.current, props: {name: `Svelte ${VERSION}`, content}});

      controller.signal.addEventListener("abort", () => {
        document.adoptedStyleSheets = document.adoptedStyleSheets.filter(sheet => sheet !== cssModule.default);
        unmount(svc);
      });
    })();  

    return () => {
      controller.abort();
    };
  }, []);

  return React.createElement('div', {ref: refDiv});
}

const root = ReactDOMClient.createRoot(document.getElementById("app"))
root.render(React.createElement(App))

    </script>

  </body>
</html>

実行すると次のような感じの描画になるはずです。
image.png

解説

import {mount, unmount, createRawSnippet} from 'svelte/';

今回は createRawSnippet を使い Svelte の Snippet を生成します。

const sv = compile(`・・・

Svelte コンポーネントを JS にコンパイルする点は前回と同じですが、Svelte コンポーネントのソースが微妙に更新されていますので確認してください。

      const content = createRawSnippet(() => ({
        render: () => `<p>Which do you like React or Svelte?</p>`,
      }));

Svelte の Snippet を構築します。

      const svc = mount(SVC.default, {target: refDiv.current, props: {name: `Svelte ${VERSION}`, content}});

Svelte の Snippet を content prop として Svelte コンポーネントに渡します。

最後に

React & Svelte ハイブリッド、最強ですね。ではまた。
Let’s have fun with React and Svelte!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?