Clientkomponenten
hono/jsx unterstützt nicht nur die Server-, sondern auch die Clientseite. Du kannst also eine interaktive Oberfläche erstellen, die im Browser läuft. Wir nennen sie Clientkomponenten oder hono/jsx/dom.
Es ist schnell und sehr klein. Das Zählerprogramm mit hono/jsx/dom ist mit Brotli-Komprimierung nur 2,8 KB groß, während es mit React 47,8 KB benötigt.
Dieser Abschnitt stellt Funktionen vor, die speziell für Clientkomponenten gedacht sind.
Zählerbeispiel
Hier ist ein Beispiel für einen einfachen Zähler. Derselbe Code funktioniert wie in 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()
Mit render() kannst du JSX-Komponenten in ein bestimmtes HTML-Element einfügen.
render(<Component />, container)Den vollständigen Beispielcode findest du hier: Zählerbeispiel.
Mit React kompatible Hooks
hono/jsx/dom bietet Hooks, die mit React vollständig oder teilweise kompatibel sind. Du kannst diese APIs anhand der React-Dokumentation kennenlernen.
useState()useEffect()useRef()useCallback()use()startTransition()useTransition()useDeferredValue()useMemo()useLayoutEffect()useReducer()useDebugValue()createElement()memo()isValidElement()useId()createRef()forwardRef()useImperativeHandle()useSyncExternalStore()useInsertionEffect()useFormStatus()useActionState()useOptimistic()
Die startViewTransition()-Familie
Die startViewTransition()-Familie enthält eigene Hooks und Funktionen, um die View Transitions API einfach zu verwenden. Die folgenden Beispiele zeigen, wie du sie nutzt.
1. Ein sehr einfaches Beispiel
Mit startViewTransition() kannst du kurz und knapp eine Transition schreiben, die document.startViewTransition verwendet.
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.dev/images/logo.png' />
) : (
<div
class={css`
background: url('https://hono.dev/images/logo-large.png');
background-size: contain;
background-repeat: no-repeat;
background-position: center;
width: 600px;
height: 600px;
`}
></div>
)}
</div>
</>
)
}2. viewTransition() mit keyframes() verwenden
Mit der Funktion viewTransition() erhältst du den eindeutigen view-transition-name.
Du kannst sie mit keyframes() verwenden. Dabei wird ::view-transition-old() in ::view-transition-old(${uniqueName)) umgewandelt.
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.dev/images/logo.png' />
) : (
<div
class={css`
${transitionNameClass}
background: url('https://hono.dev/images/logo-large.png');
background-size: contain;
background-repeat: no-repeat;
background-position: center;
width: 600px;
height: 600px;
`}
></div>
)}
</div>
</>
)
}3. useViewTransition verwenden
Wenn du den Stil nur während der Animation ändern möchtest, kannst du useViewTransition() verwenden. Dieser Hook gibt [boolean, (callback: () => void) => void] zurück: das Flag isUpdating und die Funktion startViewTransition().
Wenn dieser Hook verwendet wird, wird die Komponente zu den folgenden zwei Zeitpunkten ausgewertet.
- Innerhalb des Callbacks eines Aufrufs von
startViewTransition(). - Wenn das Promise
finisherfüllt wird.
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.dev/images/logo.png' />
) : (
<div
class={css`
${transitionNameClass}
background: url('https://hono.dev/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>
</>
)
}Die Laufzeitumgebung hono/jsx/dom
Für Clientkomponenten gibt es eine kleine JSX-Laufzeitumgebung. Ihre Verwendung erzeugt kleinere Bundles als hono/jsx. Gib hono/jsx/dom in tsconfig.json an. Für Deno ändere die deno.json.
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "hono/jsx/dom"
}
}Alternativ kannst du hono/jsx/dom in den esbuild-Transformationsoptionen in vite.config.ts angeben.
import { defineConfig } from 'vite'
export default defineConfig({
esbuild: {
jsxImportSource: 'hono/jsx/dom',
},
})