クライアントコンポーネント
hono/jsx
はサーバーサイドだけでなく、クライアントサイドもサポートしています。つまり、ブラウザで動作するインタラクティブなUIを作成することが可能です。私たちはそれをクライアントコンポーネントまたはhono/jsx/dom
と呼んでいます。
高速で非常に小さいです。 hono/jsx/dom
のカウンタープログラムは、Brotli圧縮でわずか2.8KBです。しかし、Reactの場合は47.8KBです。
このセクションでは、クライアントコンポーネント特有の機能を紹介します。
カウンターの例
単純なカウンターの例を以下に示します。Reactと同じコードが動作します。
import { useState } from 'hono/jsx'
import { render } from 'hono/jsx/dom'
function Counter() {
const [count, setCount] = useState(0)
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
)
}
function App() {
return (
<html>
<body>
<Counter />
</body>
</html>
)
}
const root = document.getElementById('root')
render(<App />, root)
render()
render()
を使用して、指定されたHTML要素内にJSXコンポーネントを挿入できます。
render(<Component />, container)
Reactと互換性のあるHooks
hono/jsx/domは、Reactと互換性があるか、部分的に互換性のあるHooksを備えています。これらのAPIについては、Reactのドキュメントを参照してください。
useState()
useEffect()
useRef()
useCallback()
use()
startTransition()
useTransition()
useDeferredValue()
useMemo()
useLayoutEffect()
useReducer()
useDebugValue()
createElement()
memo()
isValidElement()
useId()
createRef()
forwardRef()
useImperativeHandle()
useSyncExternalStore()
useInsertionEffect()
useFormStatus()
useActionState()
useOptimistic()
startViewTransition()
ファミリー
startViewTransition()
ファミリーには、View Transitions APIを簡単に扱うための独自のフックと関数が含まれています。以下は、それらの使用方法の例です。
1. 最も簡単な例
startViewTransition()
を使用すると、`document.startViewTransition`を使ったトランジションを簡単に記述できます。
import { useState, startViewTransition } from 'hono/jsx'
import { css, Style } from 'hono/css'
export default function App() {
const [showLargeImage, setShowLargeImage] = useState(false)
return (
<>
<Style />
<button
onClick={() =>
startViewTransition(() =>
setShowLargeImage((state) => !state)
)
}
>
Click!
</button>
<div>
{!showLargeImage ? (
<img src='https://hono.dokyumento.jp/images/logo.png' />
) : (
<div
class={css`
background: url('https://hono.dokyumento.jp/images/logo-large.png');
background-size: contain;
background-repeat: no-repeat;
background-position: center;
width: 600px;
height: 600px;
`}
></div>
)}
</div>
</>
)
}
2. `keyframes()`と`viewTransition()`を使用する
viewTransition()
関数を使用すると、一意の`view-transition-name`を取得できます。
これを`keyframes()`と一緒に使用できます。`::view-transition-old()`は`::view-transition-old(${uniqueName}))`に変換されます。
import { useState, startViewTransition } from 'hono/jsx'
import { viewTransition } from 'hono/jsx/dom/css'
import { css, keyframes, Style } from 'hono/css'
const rotate = keyframes`
from {
rotate: 0deg;
}
to {
rotate: 360deg;
}
`
export default function App() {
const [showLargeImage, setShowLargeImage] = useState(false)
const [transitionNameClass] = useState(() =>
viewTransition(css`
::view-transition-old() {
animation-name: ${rotate};
}
::view-transition-new() {
animation-name: ${rotate};
}
`)
)
return (
<>
<Style />
<button
onClick={() =>
startViewTransition(() =>
setShowLargeImage((state) => !state)
)
}
>
Click!
</button>
<div>
{!showLargeImage ? (
<img src='https://hono.dokyumento.jp/images/logo.png' />
) : (
<div
class={css`
${transitionNameClass}
background: url('https://hono.dokyumento.jp/images/logo-large.png');
background-size: contain;
background-repeat: no-repeat;
background-position: center;
width: 600px;
height: 600px;
`}
></div>
)}
</div>
</>
)
}
3. `useViewTransition`を使用する
アニメーション中のみスタイルを変更したい場合。 `useViewTransition()`を使用できます。このフックは`[boolean, (callback: () => void) => void]`を返し、それらは`isUpdating`フラグと`startViewTransition()`関数です。
このフックが使用されると、コンポーネントは次の2つのタイミングで評価されます。
startViewTransition()
の呼び出しのコールバック内。- `finish` promiseがfulfilledになったとき
import { useState, useViewTransition } from 'hono/jsx'
import { viewTransition } from 'hono/jsx/dom/css'
import { css, keyframes, Style } from 'hono/css'
const rotate = keyframes`
from {
rotate: 0deg;
}
to {
rotate: 360deg;
}
`
export default function App() {
const [isUpdating, startViewTransition] = useViewTransition()
const [showLargeImage, setShowLargeImage] = useState(false)
const [transitionNameClass] = useState(() =>
viewTransition(css`
::view-transition-old() {
animation-name: ${rotate};
}
::view-transition-new() {
animation-name: ${rotate};
}
`)
)
return (
<>
<Style />
<button
onClick={() =>
startViewTransition(() =>
setShowLargeImage((state) => !state)
)
}
>
Click!
</button>
<div>
{!showLargeImage ? (
<img src='https://hono.dokyumento.jp/images/logo.png' />
) : (
<div
class={css`
${transitionNameClass}
background: url('https://hono.dokyumento.jp/images/logo-large.png');
background-size: contain;
background-repeat: no-repeat;
background-position: center;
width: 600px;
height: 600px;
position: relative;
${isUpdating &&
css`
&:before {
content: 'Loading...';
position: absolute;
top: 50%;
left: 50%;
}
`}
`}
></div>
)}
</div>
</>
)
}
hono/jsx/dom
ランタイム
クライアントコンポーネント用の小さなJSXランタイムがあります。これを使用すると、`hono/jsx`を使用するよりもバンドル結果が小さくなります。 `tsconfig.json`で`hono/jsx/dom`を指定します。
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "hono/jsx/dom"
}
}