概要:
Astro2 で、フロントでReactを使えるか試す編です。
-
ベース部分は Astro SSR, ルーティング機能など
-
svelteKit 使うほうがシンプルですね。。
-
フロントJSで、ReactをCDNから読込んで使ってみました。
構成
- Astro: 2
- React 18
参考
参考のコード
実装の例
- test/indes.astro
---
import Layout from '../../layouts/Layout.astro';
const PUBLIC_ANYBODY = import.meta.env.PUBLIC_ANYBODY;
const url = import.meta.env.PUBLIC_API_URL;
console.log("url=", url);
---
<!-- MarkUp -->
<Layout title="Welcome to Astro.">
<div id="root" class="container">
</div>
</Layout>
<!-- -->
<style>
</style>
<!-- -->
<script is:inline src="/js/Test.js"></script>
<script type="text/babel">
const useState = React.useState;
const useEffect = React.useEffect;
//Test.func1();
//
const App = () => {
const [state, setState] = useState(0)
const handleClick = () => setState(state + 1);
return (
<div>
<h1>My React App with CDN</h1>
<hr />
カウント: {state}
<hr />
<button onClick={handleClick}>TestCount</button>
</div>
)
}
const container = document.getElementById("root");
const root = ReactDOM.createRoot(container);
root.render(<App />);
</script>
-
Layout: CDNで、React読込む例です。
-
script is:inline で、CDNファイル読みます。
---
export interface Props {
title: string;
}
const { title } = Astro.props;
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="generator" content={Astro.generator} />
<title>{title}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/css/bootstrap.min.css"
rel="stylesheet" integrity="sha384-+0n0xVW2eSR5OomGNYDnhzAbDsOXxcvSN1TPprVMTNDbiYZCxYbOOl7+AMvyTG2x" crossorigin="anonymous" />
<!-- SQLITE -->
<script is:inline src="https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.6.2/sql-wasm.min.js"></script>
<!-- React -->
<script is:inline src="https://unpkg.com/react@18/umd/react.production.min.js" crossorigin></script>
<script is:inline src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js" crossorigin></script>
<script is:inline src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<!-- Header -->
<div class="text-center my-2">
<a href={`/`}>[ Top ]</a>
<a href={`/test`}>[ Test ]</a>
<a href={`/gpt`}>[ GPT ]</a>
<hr />
</div>
<slot />
</body>
</html>
<style is:global>
:root {
--accent: 124, 58, 237;
--accent-gradient: linear-gradient(45deg, rgb(var(--accent)), #da62c4 30%, white 60%);
}
html {
font-family: system-ui, sans-serif;
background-color: #F6F6F6;
}
code {
font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
Bitstream Vera Sans Mono, Courier New, monospace;
}
</style>
<script src="../lib/Layout.ts"></script>
<!--
<a href={`/login`}>[ Login ]</a>
-->
- 追加
- useState, useEffect
- component, prop
- map 繰り返し
---
import Layout from '../../layouts/Layout.astro';
const PUBLIC_ANYBODY = import.meta.env.PUBLIC_ANYBODY;
const url = import.meta.env.PUBLIC_API_URL;
console.log("url=", url);
---
<!-- MarkUp -->
<Layout title="Welcome to Astro.">
<div id="root" class="container">
</div>
</Layout>
<!-- -->
<style>
</style>
<!-- -->
<script is:inline src="/js/Test.js"></script>
<script is:inline type="text/babel" src="/js/components/Child.js"></script>
<script type="text/babel">
const useState = React.useState;
const useEffect = React.useEffect;
//
const App = () => {
const [state, setState] = useState(0)
const [count, setCount] = useState(0);
const [items, setItems] = useState([])
const handleClick = () => setState(state + 1);
const greeting = 'Welcome , React !!!';
//
useEffect(() => {
const testItems =Test.getList();
setItems(testItems);
console.log(testItems);
}, []);
//
return (
<div>
<h1>My React Title</h1>
<hr />
カウント: {state}
<hr />
<button onClick={handleClick}>TestCount</button>
<hr />
<Child text={greeting} />
<hr />
<button onClick={() => setCount(count + 1)}>
Click me
</button>
<hr />
{items.map((item, index) => {
return (
<div key={item.id}>ID: {item.id}, Name: {item.name}
</div>
)
})}
</div>
)
}
const container = document.getElementById("root");
const root = ReactDOM.createRoot(container);
root.render(<App />);
</script>
-
CRUD の一部
-
/src/pages/gpt2/index.astro
---
import Layout from '../../layouts/Layout.astro';
import CrudIndex from './CrudIndex';
const url = import.meta.env.PUBLIC_API_URL;
let serverConfig = {url: url};
serverConfig = JSON.stringify(serverConfig);
console.log(serverConfig);
---
<Layout title="Welcome to Astro.">
<main class="container">
<input type="hidden" id="server_config" value={serverConfig}>
</input>
<h1>Gpt2-React</h1>
<a href={`/gpt2/create`} class="btn btn-primary">Create</a>
<hr />
<div id="root"></div>
<hr />
</main>
</Layout>
<!-- -->
<style>
</style>
<!-- JS -->
<script is:inline src="/js/Test.js"></script>
<script is:inline src="/js/lib/todo/Crud.js"></script>
<script is:inline src="/js/lib/Common.js"></script>
<script is:inline type="text/babel" src="/js/components/Child.js"></script>
<script is:inline type="text/babel" src="/js/lib/todo/main.js"></script>
<!--
-->
- main.js : public/js/lib/todo/main.js
main.js
const prmServer = Common.getServerConfig();
console.log(prmServer);
const useState = React.useState;
const useEffect = React.useEffect;
//
const App = () => {
const [items, setItems] = useState([])
//
useEffect(async() => {
const testItems = await Crud.getList(prmServer);
setItems(testItems);
console.log(testItems);
}, []);
//
return (
<div>
{items.map((item, index) => {
return (
<div key={item.id}>
<h3>{item.title}</h3>
ID: {item.id}
<span class="mx-2">
<a href={`/gpt2/show/${item.id}`} class="btn btn-sm btn-outline-primary"
>Show</a>
</span>
<hr class="my-2" />
</div>
)
})}
</div>
)
}
const container = document.getElementById("root");
const root = ReactDOM.createRoot(container);
root.render(<App />);
....