CodePenでesm.shでお手軽にReact RouterとReact Three Fiberを連携させてみるテスト
前回の作業のReact Routerを使用したコードでは自分の思うようなレイアウトを作成するまでの道のりは遠そうだったので、とりあえずそれは保留にしておき、本来の目標であったReact RouterとReact Three Fiberを連携させてみました。
React RouterとReact Three Fiberを連携させるまでの過程
■React Three Fiber 8.15.12 & React Router 6.22.3 Test01(失敗)
まず最初に
・ryanflorence/react-three-routes.jsx
や
・React Router Context broken #486
といったサイト・コードを参考にさせていただき、RoutesをCanvasで挟むようなコードを作成したものです。 全然動きませんでしたw。 失敗です。
React RouterとThree.jsの連携では、他にもContextのhistoryを使用したものも見かけましたが、そちらはコードが複雑になりそうなので今回は取り扱わないことにしました。
■React Three Fiber 8.15.12 & React Router 6.22.3 Test02(失敗)
Test01を修正して少し動くようになったものです。 RoutesをCanvasで挟んだところの一部分が動くようになりました。 が、Canvasで挟んだところは全てThree React Fiberで作成しなければならないようで、(Three React Fiberでない)普通のh1を設定しているところは表示しようとするとエラーになってしまいます。
コードの実行時は「Home」「About」「Test」とある選択肢のうち、「Test」をクリックしたときだけ動きます。 「Home」「About」をクリックした場合は画面に何も表示されなくなり、それ以上操作できなくなります。
■React Three Fiber 8.15.12 & React Router 6.22.3 Test03(失敗)
Test02の「Home」「About」「Test」の選択肢から「About」「Test」を動くようにしたものです。 「Home」選択時はひきつづき操作できなくなる状態です。
最初はエラーの状況がわからなかったので、上記Test02の説明でも書いていた、Canvasで挟んだところは全てThree React Fiberにしなければならない、ということを確認するためにTest02からの差分的に作成したものです。
■React Three Fiber 8.15.12 & React Router 6.22.3 Test04
Test03から引き継いだ「Home」「About」「Test」の選択肢をすべて動くように修正したものです。 Three React Fiber使用のためにCanvasで挟んでしまうRoutes内の遷移先はすべてThree React Fiber要素で作成しなければならないようですが、とりあえずThree React FiberとReact Routerの連携成功ということにしています。 なのでやっと(失敗)の文字が消えましたw。
■React Three Fiber 8.15.12 & React Router 6.22.3 Test05
「Home」「About」「Test」を選択時に表示される3Dオブジェクトをそれぞれ、Box、Plane、Sphereに変更しました。
React RouterとReact Three Fiberを連携させた成果物
■React Three Fiber 8.15.12 & React Router 6.22.3 Test06
今回の成果物となります。 画面とコードのコピペを貼り付けてみます。
Test05からの変更点は「Home」「About」「Test」と表示される選択肢を、表示される3Dオブジェクトに合わせて「Box」「Plane」「Sphere」としたことだけです。 React RouterとReact Three Fiberの連携のための、ビビリながら・手探りしながらのコーディングだったので変更点が毎回極小になりがちとなっていますw。
HTML
<div id="root"></div>
CSS なし
* {
box-sizing: border-box;
}
html,
body,
#root {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
body {
background: #f0f0f0;
}
JS(JavaScript)
import React, { useRef, useState } from 'https://esm.sh/react@18.2.0'
import ReactDOM from "https://esm.sh/react-dom@18.2.0";
import {
BrowserRouter,
Link,
Routes,
Route
} from "https://esm.sh/react-router-dom@6.22.3";
import { Canvas, useFrame } from 'https://esm.sh/@react-three/fiber@8.15.12'
import { DoubleSide } from 'https://esm.sh/three@0.163.0'
const App = () => {
return (
<>
<h1>hello react router v6</h1>
<ul>
<li>
<Link to="/">Box</Link>
</li>
<li>
<Link to="/plane">Plane</Link>
</li>
<li>
<Link to="/sphere">Sphere</Link>
</li>
</ul>
<Canvas>
<ambientLight intensity={Math.PI / 2} />
<spotLight position={[10, 10, 10]} angle={0.15} penumbra={1} decay={0} intensity={Math.PI} />
<pointLight position={[-10, -10, -10]} decay={0} intensity={Math.PI} />
<Routes>
<Route path="/" element={<Box position={[0, 0, 2.5]} />}></Route>
<Route path="/plane" element={<Plane position={[0, 0, 0]} />}></Route>
<Route path="/sphere" element={<Sphere position={[0, 0, 0]} />}></Route>
</Routes>
</Canvas>
</>
);
}
// Box Start /////////////////////////////////////////////////////////////////////////////
const Box = (props) => {
const meshRef = useRef();
const [hovered, setHover] = useState(false)
const [active, setActive] = useState(false)
useFrame((state, delta) => (meshRef.current.rotation.x += delta))
return (
<mesh
{...props}
ref={meshRef}
scale={active ? 1.5 : 1}
onClick={(event) => setActive(!active)}
onPointerOver={(event) => setHover(true)}
onPointerOut={(event) => setHover(false)}>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color={hovered ? 'hotpink' : 'orange'} />
</mesh>
)
}
// Box End ///////////////////////////////////////////////////////////////////////////////
// Plane Start ///////////////////////////////////////////////////////////////////////////
const Plane = (props) => {
const meshRef = useRef();
const [hovered, setHover] = useState(false)
const [active, setActive] = useState(false)
useFrame((state) => {
meshRef.current.rotation.x = state.mouse.x * 5
meshRef.current.rotation.y = state.mouse.y * 5
}, [])
return (
<mesh
{...props}
ref={meshRef}
scale={active ? 1.5 : 1}
onClick={(event) => setActive(!active)}
onPointerOver={(event) => setHover(true)}
onPointerOut={(event) => setHover(false)}>
<planeGeometry args={[2, 2, 2]} />
<meshStandardMaterial color={hovered ? 'red' : 'blue'} side={DoubleSide} />
</mesh>
)
}
// Plane End /////////////////////////////////////////////////////////////////////////////
// Sphere Start //////////////////////////////////////////////////////////////////////////
const Sphere = (props) => {
const meshRef = useRef();
const [hovered, setHover] = useState(false)
const [active, setActive] = useState(false)
useFrame((state) => {
meshRef.current.rotation.x = state.mouse.x * 5
meshRef.current.rotation.y = state.mouse.y * 5
}, [])
return (
<mesh
{...props}
ref={meshRef}
scale={active ? 1.5 : 1}
onClick={(event) => setActive(!active)}
onPointerOver={(event) => setHover(true)}
onPointerOut={(event) => setHover(false)}>
<sphereGeometry args={[2, 25, 25]} />
<meshStandardMaterial wireframe color={hovered ? 'red' : 'blue'} />
</mesh>
)
}
// Sphere End ////////////////////////////////////////////////////////////////////////////
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root")
);
次はTailwindCSSを加えて、最終目標のReact Three FiberとReact RouterとTailwindCSSを、esm.shやCDNを使用してCodePenでよしなに連携できるかのテストを行っていく予定です。
参考にさせていただいたサイト・コード
以下のコードとサイトを参考にさせていただきました
React Three Fiber > GETTING STARTED > Introduction
ryanflorence/react-three-routes.jsx
React Router Context broken #486
Context Lost when I route to another page in react three fiber
自分で作成した以下のコードも参考にしました
React Three Fiber 8.15.12 Test02
React Three Fiber 8.15.12 Test05 Sphere
React Three Fiber 8.15.12 Test04 Plane
React Three Fiber 8.15.12 Test03 Box