Skip to content

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',
    }
  )
})

Hono v4.9 中文网 - 粤ICP备13048890号