0.2.0 • Published 23 days ago

@hono/react-renderer v0.2.0

Weekly downloads
-
License
MIT
Repository
github
Last release
23 days ago

React Renderer Middleware

React Renderer Middleware allows for the easy creation of a renderer based on React for Hono.

Installation

npm i @hono/react-renderer react react-dom hono
npm i -D @types/react @types/react-dom

Settings

tsconfig.json:

{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "react"
  }
}

Usage

Basic

import { Hono } from 'hono'
import { reactRenderer } from '@hono/react-renderer'

const app = new Hono()

app.get(
  '*',
  reactRenderer(({ children }) => {
    return (
      <html>
        <body>
          <h1>React + Hono</h1>
          <div>{children}</div>
        </body>
      </html>
    )
  })
)

app.get('/', (c) => {
  return c.render(<p>Welcome!</p>)
})

Extending Props

You can define types of Props:

declare module '@hono/react-renderer' {
  interface Props {
    title: string
  }
}

Then, you can use it in the reactRenderer() function and pass values as a second argument to c.render():

app.get(
  '*',
  reactRenderer(({ children, title }) => {
    return (
      <html>
        <head>
          <title>{title}</title>
        </head>
        <body>
          <div>{children}</div>
        </body>
      </html>
    )
  })
)

app.get('/', (c) => {
  return c.render(<p>Welcome!</p>, {
    title: 'Top Page',
  })
})

useRequestContext()

You can get an instance of Context in a function component:

const Component = () => {
  const c = useRequestContext()
  return <p>You access {c.req.url}</p>
}

app.get('/', (c) => {
  return c.render(<Component />)
})

Options

docType

If you set it true, DOCTYPE will be added:

app.get(
  '*',
  reactRenderer(
    ({ children }) => {
      return (
        <html>
          <body>
            <div>{children}</div>
          </body>
        </html>
      )
    },
    {
      docType: true,
    }
  )
)

The HTML is the following:

<!DOCTYPE html>
<html>
  <body>
    <div><p>Welcome!</p></div>
  </body>
</html>

You can specify the docType as you like.

app.get(
  '*',
  reactRenderer(
    ({ children }) => {
      return (
        <html>
          <body>
            <div>{children}</div>
          </body>
        </html>
      )
    },
    {
      docType:
        '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
    }
  )
)

stream

It enables returning a streaming response. You can use a Suspense with it:

import { reactRenderer } from '@hono/react-renderer'
import { Suspense } from 'react'

app.get(
  '*',
  reactRenderer(
    ({ children }) => {
      return (
        <html>
          <body>
            <div>{children}</div>
          </body>
        </html>
      )
    },
    {
      stream: true,
    }
  )
)

let done = false

const Component = () => {
  if (done) {
    return <p>Done!</p>
  }
  throw new Promise((resolve) => {
    done = true
    setTimeout(resolve, 1000)
  })
}

app.get('/', (c) => {
  return c.render(
    <Suspense fallback='loading...'>
      <Component />
    </Suspense>
  )
})

Limitation

A streaming feature is not available on Vite or Vitest.

Author

Yusuke Wada https://github.com/yusukebe

License

MIT

0.2.0

23 days ago

0.1.1

2 months ago

0.1.0

2 months ago

0.0.2

5 months ago

0.0.1

5 months ago