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