かなりのレアケースではありますが、例えば React を使った Web Components のカスタム要素を複数定義する場合などで、 Root#render()
を複数回呼び出すことがあります。
src/index.tsx
import { createRoot } from "react-dom/client";
import { App } from "./App";
import { Button } from "./Button";
class MyButton extends HTMLElement {
connectedCallback() {
const shadow = this.attachShadow({ mode: "closed" });
const root = createRoot(shadow);
root.render(<Button />);
}
}
class MyApp extends HTMLElement {
connectedCallback() {
const shadow = this.attachShadow({ mode: "closed" });
const root = createRoot(shadow);
root.render(<App />);
}
}
customElements.define("my-button", MyButton);
customElements.define("my-app", MyApp);
また更にレアケースですが、このカスタム要素間で状態を共有したい場合があります。
当然ながら React 自体に Root#render()
間を跨いで状態を共有する方法はありませんが、React の外側で確保したメモリをポーリングするすることでそれっぽいことができます。
src/utils/str.ts
export let str = "aaa";
export function setStr(s: string) {
str = s;
}
src/Button.tsx
import { setStr } from "./utils/str";
export function Button() {
return (
<button
onClick={() => {
setStr("bbb");
}}
>
set "bbb"
</button>
);
}
src/App.tsx
import { useEffect, useState } from "react";
import { str } from "./utils/str";
export function App() {
const [text, setText] = useState(str);
useEffect(() => {
const id = setInterval(() => {
if (str !== text) {
setText(str);
}
}, 1000);
return () => {
clearInterval(id);
};
}, []);
return <span>テキスト: {text}</span>;
}
ボタンをクリックすると、少し遅れてテキストが bbb
に変わります。
こんな怪しいアイデアが役に立って欲しくはありませんが、もし何かの刺激になれば幸いです。
今回紹介したコードはこちらのリポジトリにもプッシュしているので、興味のある方は覗いてみてください。
(もっと良いやり方をご存知の方がいれば、コメントにてお教えください。)