客户端组件
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 兼容的 Hook
hono/jsx/dom 具有与 React 兼容或部分兼容的 Hook。您可以查看 React 文档 来了解这些 API。
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 的原始 Hook 和函数。以下是使用它们的示例。
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.node.org.cn/images/logo.png' />
) : (
<div
class={css`
background: url('https://hono.node.org.cn/images/logo-large.png');
background-size: contain;
background-repeat: no-repeat;
background-position: center;
width: 600px;
height: 600px;
`}
></div>
)}
</div>
</>
)
}
2. 使用 viewTransition()
和 keyframes()
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.node.org.cn/images/logo.png' />
) : (
<div
class={css`
${transitionNameClass}
background: url('https://hono.node.org.cn/images/logo-large.png');
background-size: contain;
background-repeat: no-repeat;
background-position: center;
width: 600px;
height: 600px;
`}
></div>
)}
</div>
</>
)
}
3. 使用 useViewTransition
如果您只想在动画期间更改样式。您可以使用 useViewTransition()
。此 Hook 返回 [boolean, (callback: () => void) => void]
,它们分别是 isUpdating
标志和 startViewTransition()
函数。
使用此 Hook 时,组件将在以下两个时间点进行评估。
- 在调用
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.node.org.cn/images/logo.png' />
) : (
<div
class={css`
${transitionNameClass}
background: url('https://hono.node.org.cn/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"
}
}