Remixでreact-konvaを使う
Full Stack Web FrameworkのRemixに、Canvasを扱うライブラリreact-konvaを導入する方法について記載します。
Remixのプロジェクトは作成済みで、パッケージ管理のためにpnpmを利用しているものとします。
react-konvaをインストールします。
pnpm install react-konva konva
READMEに従い、Canvasを描画するコンポーネントを作成します。
import { Circle, Layer, Rect, Stage } from "react-konva";
export const MyCanvas = () => {
return (
<Stage width={window.innerWidth} height={window.innerHeight}>
<Layer>
<Rect width={50} height={50} fill="red" />
<Circle x={200} y={200} stroke="black" radius={50} />
</Layer>
</Stage>
);
};
呼び出し元のページに先ほどのコンポーネントを追加します。
import { json } from "@remix-run/node";
import { MyCanvas } from "./components/my-canvas";
export const loader = () => {
return json({});
};
export default function Index() {
return (
<div>
<MyCanvas />
</div>
);
}
pnpm dev
でdev serverを起動し対象ページにアクセスとすると、次のようなエラーとなります。
pnpm preview
で一旦buildしたものをプレビューすると、次のようなエラーとなります。
Canvas周りはSSRと相性が悪いようで、CanvasのみClient Sideで処理するよう指定する必要があります。
Canvasはブラウザで動作するためDOMのwindowが必要です。条件付きレンダリングしてあげます。
import { json } from "@remix-run/node";
import { MyCanvas } from "./components/my-canvas";
export const loader = () => {
return json({});
};
export default function Index() {
return (
<div>
- <MyCanvas />
+ {typeof window !== "undefined" && <MyCanvas />}
</div>
);
}
更に、Canvasを描画するコンポーネントの名前を my-canvas.tsx
から my-canvas.client.tsx
に変更します。
これによりコンポーネントはClient modulesとして扱われるため、Canvasが描画できるようになります。
以下、参考となったIssueです。
しかし、これでもまだエラーが残ります。
どうやら {typeof window !== "undefined" && <MyCanvas />}
での条件付きレンダリングがうまくいっていないようです。
Reactのhydrationの公式Docに従い、 window
ではなく Client Sideでのみ実行される useEffect
を利用してCanvasを描画するようにします。
+import { useEffect, useState } from "react";
import { json } from "@remix-run/node";
import { MyCanvas } from "./components/my-canvas";
export const loader = () => {
return json({});
};
export default function Index() {
+ const [isClient, setIsClient] = useState(false);
+ useEffect(() => {
+ setIsClient(true);
+ }, []);
return (
<div>
- {typeof window !== "undefined" && <MyCanvas />}
+ {isClient ? (
+ <MyCanvas />
+ ) : <div />}
</div>
);
}
これで全てのエラーが解消され、Canvasが安定して描画されるようになりました。
Discussion