JSX 렌더러 미들웨어
JSX 렌더러 미들웨어를 사용하면 c.setRenderer()를 사용하지 않고도 c.render() 함수로 JSX를 렌더링할 때 레이아웃을 설정할 수 있다. 또한 useRequestContext()를 통해 컴포넌트 내에서 Context 인스턴스에 접근할 수 있다.
임포트
ts
import { Hono } from 'hono'
import { jsxRenderer, useRequestContext } from 'hono/jsx-renderer'사용법
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>)
})옵션
optional docType: boolean | string
HTML의 시작 부분에 DOCTYPE을 추가하지 않으려면 docType 옵션을 false로 설정한다.
tsx
app.use(
'*',
jsxRenderer(
({ children }) => {
return (
<html>
<body>{children}</body>
</html>
)
},
{ docType: false }
)
)또한 사용자 정의 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">',
}
)
)optional stream: boolean | Record<string, string>
true로 설정하거나 Record 값을 제공하면 스트리밍 응답으로 렌더링된다.
tsx
const AsyncComponent = async () => {
await new Promise((r) => setTimeout(r, 1000)) // 1초 대기
return <div>Hi!</div>
}
app.get(
'*',
jsxRenderer(
({ children }) => {
return (
<html>
<body>
<h1>SSR 스트리밍</h1>
{children}
</body>
</html>
)
},
{ stream: true }
)
)
app.get('/', (c) => {
return c.render(
<Suspense fallback={<div>loading...</div>}>
<AsyncComponent />
</Suspense>
)
})true로 설정하면 다음과 같은 헤더가 추가된다:
ts
{
'Transfer-Encoding': 'chunked',
'Content-Type': 'text/html; charset=UTF-8',
'Content-Encoding': 'Identity'
}Record 값을 지정해 헤더 값을 커스터마이징할 수 있다.
중첩 레이아웃
Layout 컴포넌트를 사용하면 레이아웃을 중첩할 수 있다.
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 인스턴스를 반환한다.
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>
현재 접속 중인 URL: <RequestUrlBadge />
</div>
)
})WARNING
Deno의 precompile JSX 옵션과 함께 useRequestContext()를 사용할 수 없다. 대신 react-jsx를 사용한다:
json
"compilerOptions": {
"jsx": "precompile",
"jsx": "react-jsx",
"jsxImportSource": "hono/jsx"
}
}ContextRenderer 확장하기
아래와 같이 ContextRenderer를 정의하면 렌더러에 추가적인 내용을 전달할 수 있다. 예를 들어, 페이지에 따라 head 태그의 내용을 변경하고 싶을 때 유용하다.
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',
}
)
})