Appearance
JSX 渲染器中间件
¥JSX Renderer Middleware
JSX Renderer Middleware 允许你在使用 c.render()
函数渲染 JSX 时设置布局,而无需使用 c.setRenderer()
。此外,它通过使用 useRequestContext()
允许访问组件内的 Context 实例。
¥JSX Renderer Middleware allows you to set up the layout when rendering JSX with the c.render()
function, without the need for using c.setRenderer()
. Additionally, it enables access to instances of Context within components through the use of useRequestContext()
.
导入
¥Import
ts
import { Hono } from 'hono'
import { jsxRenderer, useRequestContext } from 'hono/jsx-renderer'
用法
¥Usage
jsx
const app = new Hono()
app.get(
'/page/*',
jsxRenderer(({ children }) => {
return (
<html>
<body>
<header>Menu</header>
<div>{children}</div>
</body>
</html>
)
})
)
app.get('/page/about', (c) => {
return c.render(<h1>About me!</h1>)
})
选项
¥Options
optional docType:boolean
| string
如果你不想在 HTML 开头添加 DOCTYPE,请将 docType
选项设置为 false
。
¥If you do not want to add a DOCTYPE at the beginning of the HTML, set the docType
option to false
.
tsx
app.use(
'*',
jsxRenderer(
({ children }) => {
return (
<html>
<body>{children}</body>
</html>
)
},
{ docType: false }
)
)
你可以指定 DOCTYPE。
¥And you can specify the DOCTYPE.
tsx
app.use(
'*',
jsxRenderer(
({ children }) => {
return (
<html>
<body>{children}</body>
</html>
)
},
{
docType:
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
}
)
)
<徽章类型="info" 文本="optional" /> 流:boolean
| Record<string, string>
¥optional stream: boolean
| Record<string, string>
如果你将其设置为 true
或提供 Record 值,它将被渲染为流式响应。
¥If you set it to true
or provide a Record value, it will be rendered as a streaming response.
tsx
const AsyncComponent = async () => {
await new Promise((r) => setTimeout(r, 1000)) // sleep 1s
return <div>Hi!</div>
}
app.get(
'*',
jsxRenderer(
({ children }) => {
return (
<html>
<body>
<h1>SSR Streaming</h1>
{children}
</body>
</html>
)
},
{ stream: true }
)
)
app.get('/', (c) => {
return c.render(
<Suspense fallback={<div>loading...</div>}>
<AsyncComponent />
</Suspense>
)
})
如果设置了 true
,则添加以下标头:
¥If true
is set, the following headers are added:
ts
{
'Transfer-Encoding': 'chunked',
'Content-Type': 'text/html; charset=UTF-8',
'Content-Encoding': 'Identity'
}
你可以通过指定记录值来自定义标头值。
¥You can customize the header values by specifying the Record values.
嵌套布局
¥Nested Layouts
Layout
组件允许嵌套布局。
¥The Layout
component enables nesting the layouts.
tsx
app.use(
jsxRenderer(({ children }) => {
return (
<html>
<body>{children}</body>
</html>
)
})
)
const blog = new Hono()
blog.use(
jsxRenderer(({ children, Layout }) => {
return (
<Layout>
<nav>Blog Menu</nav>
<div>{children}</div>
</Layout>
)
})
)
app.route('/blog', blog)
useRequestContext()
useRequestContext()
返回 Context 的实例。
¥useRequestContext()
returns an instance of Context.
tsx
import { useRequestContext, jsxRenderer } from 'hono/jsx-renderer'
const app = new Hono()
app.use(jsxRenderer())
const RequestUrlBadge: FC = () => {
const c = useRequestContext()
return <b>{c.req.url}</b>
}
app.get('/page/info', (c) => {
return c.render(
<div>
You are accessing: <RequestUrlBadge />
</div>
)
})
警告
你不能将 useRequestContext()
与 Deno 的 precompile
JSX 选项一起使用。使用 react-jsx
:
¥You can't use useRequestContext()
with the Deno's precompile
JSX option. Use the react-jsx
:
json
"compilerOptions": {
"jsx": "precompile",
"jsx": "react-jsx",
"jsxImportSource": "hono/jsx"
}
}
扩展 ContextRenderer
¥Extending ContextRenderer
通过定义 ContextRenderer
(如下所示),你可以将其他内容传递给渲染器。例如,当你想要根据页面更改 head 标签的内容时,这很方便。
¥By defining ContextRenderer
as shown below, you can pass additional content to the renderer. This is handy, for instance, when you want to change the contents of the head tag depending on the page.
tsx
declare module 'hono' {
interface ContextRenderer {
(
content: string | Promise<string>,
props: { title: string }
): Response
}
}
const app = new Hono()
app.get(
'/page/*',
jsxRenderer(({ children, title }) => {
return (
<html>
<head>
<title>{title}</title>
</head>
<body>
<header>Menu</header>
<div>{children}</div>
</body>
</html>
)
})
)
app.get('/page/favorites', (c) => {
return c.render(
<div>
<ul>
<li>Eating sushi</li>
<li>Watching baseball games</li>
</ul>
</div>,
{
title: 'My favorites',
}
)
})