初めに
React 19 で use()
なる新しい Hook が登場しそうなので、あたふたしないように今のうちに慣れておきましょう。
- 作者注(2024/04/27)
use()
が、React@18.3 ではなく React@19 で搭載されることになりましたのでソース(sample2.html)を変更いたしました。なお、React@19 では umd 版の配布がなくなるため、CDN からの React の読み込み方法も変更しておりますが。その部分が本質ではありませんので惑わされないように注意してください。
本題
いきなりですがソースです。
賢い人達にはすでにお馴染みの(?) Render-as-You-Fetch を駆使した React@18.2 までの旧来のソースです。
sample1.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
</head>
<body>
<div id="app"></div>
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<script>
////////////////////////////////////////////////////
// Render-as-You-Fetch
// https://reactjs.org/docs/concurrent-mode-suspense.html#approach-3-render-as-you-fetch-using-suspense
const wrapPromise = promise => {
let status = "pending"
let result
const suspender = promise.then(
r => {
status = "success"
result = r
},
e => {
status = "error"
result = e
}
)
return {
read() {
if (status === "pending") {
throw suspender
} else if (status === "error") {
throw result
} else if (status === "success") {
return result
}
}
}
}
//
const resource = wrapPromise(
(async() => {
const r = await fetch('https://www.reddit.com/r/reactjs.json')
return await r.json()
})()
)
//
const Inner = props => {
const json = resource.read()
const posts = json.data.children.map((child) => child.data);
return posts.map(post =>
React.createElement('div', {key: post.id}, post.title)
)
}
//
const App = props => {
return React.createElement(React.Suspense,
{
fallback: React.createElement('p', {}, 'Now Loading...')
},
React.createElement(Inner)
)
}
const root = ReactDOM.createRoot(document.getElementById("app"))
root.render(React.createElement(App))
////////////////////////////////////////////////////
</script>
</body>
</html>
いよいよ、皆様お待ちかね(?)の use()
を使用した最新のソースです。だいぶすっきりしました!
sample2.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
</head>
<body>
<div id="app"></div>
<script type="module">
import React from "https://esm.sh/react@beta?dev";
import ReactDOM from "https://esm.sh/react-dom@beta?dev";
import ReactDOMClient from "https://esm.sh/react-dom@beta/client?dev";
// import ReactDOMServer from "https://esm.sh/react-dom@beta/server.browser?dev";
window.React = React;
window.ReactDOM = ReactDOM;
window.ReactDOMClient = ReactDOMClient;
// window.ReactDOMServer = ReactDOMServer;
</script>
<script type="module">
////////////////////////////////////////////////////
//
const resource = (async() => {
const r = await fetch('https://www.reddit.com/r/reactjs.json')
return await r.json()
})()
//
const Inner = props => {
const json = React.use(resource)
const posts = json.data.children.map((child) => child.data);
return posts.map(post =>
React.createElement('div', {key: post.id}, post.title)
)
}
//
const App = props => {
return React.createElement(React.Suspense,
{
fallback: React.createElement('p', {}, 'Now Loading...')
},
React.createElement(Inner)
)
}
const root = ReactDOMClient.createRoot(document.getElementById("app"))
root.render(React.createElement(App))
////////////////////////////////////////////////////
</script>
</body>
</html>
最後に
上記のソースを見比べれば React@19 で慌てることも騒ぐこともなくなるはずです。
前回投稿したSignalsもどきと組み合わせればいよいよ最強の React マスターも目前といっても過言ではないでしょう。
最後まで拙文を読んでいただきありがとうございました<(_ _)>