Aller au contenu

Composants côté client ​

hono/jsx prend en charge le rendu côté serveur et côté client. Vous pouvez donc créer une interface interactive qui s'exécute dans le navigateur. Nous appelons cela les composants côté client, ou hono/jsx/dom.

C'est rapide et très léger. Le programme de compteur avec hono/jsx/dom ne pèse que 2,8 Ko avec la compression Brotli, contre 47,8 Ko pour React.

Cette section présente les fonctionnalités propres aux composants côté client.

Exemple de compteur ​

Voici un exemple de compteur simple, dont le code fonctionne comme avec React.

tsx
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() ​

Vous pouvez utiliser render() pour insérer des composants JSX dans un élément HTML donné.

tsx
render(<Component />, container)

Vous trouverez le code complet ici : exemple de compteur.

Hooks compatibles avec React ​

hono/jsx/dom propose des hooks compatibles ou partiellement compatibles avec React. Vous pouvez découvrir ces API dans la documentation React.

  • useState()
  • useEffect()
  • useRef()
  • useCallback()
  • use()
  • startTransition()
  • useTransition()
  • useDeferredValue()
  • useMemo()
  • useLayoutEffect()
  • useReducer()
  • useDebugValue()
  • createElement()
  • memo()
  • isValidElement()
  • useId()
  • createRef()
  • forwardRef()
  • useImperativeHandle()
  • useSyncExternalStore()
  • useInsertionEffect()
  • useFormStatus()
  • useActionState()
  • useOptimistic()

Famille startViewTransition() ​

La famille startViewTransition() contient des hooks et des fonctions propres à Hono qui facilitent l'utilisation de l'API View Transitions. Les exemples ci-dessous montrent comment les utiliser.

1. Exemple très simple ​

Vous pouvez écrire de façon concise une transition reposant sur document.startViewTransition avec startViewTransition().

tsx
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.dev/images/logo.png' />
        ) : (
          <div
            class={css`
              background: url('https://hono.dev/images/logo-large.png');
              background-size: contain;
              background-repeat: no-repeat;
              background-position: center;
              width: 600px;
              height: 600px;
            `}
          ></div>
        )}
      </div>
    </>
  )
}

2. Utiliser viewTransition() avec keyframes() ​

La fonction viewTransition() permet d'obtenir un view-transition-name unique.

Vous pouvez l'utiliser avec keyframes() ; ::view-transition-old() est converti en ::view-transition-old(${uniqueName)).

tsx
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.dev/images/logo.png' />
        ) : (
          <div
            class={css`
              ${transitionNameClass}
              background: url('https://hono.dev/images/logo-large.png');
              background-size: contain;
              background-repeat: no-repeat;
              background-position: center;
              width: 600px;
              height: 600px;
            `}
          ></div>
        )}
      </div>
    </>
  )
}

3. Utiliser useViewTransition ​

Pour changer le style uniquement pendant l'animation, utilisez useViewTransition(). Ce hook renvoie [boolean, (callback: () => void) => void], soit le flag isUpdating et la fonction startViewTransition().

Lorsque ce hook est utilisé, le composant est évalué aux deux moments suivants.

tsx
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.dev/images/logo.png' />
        ) : (
          <div
            class={css`
              ${transitionNameClass}
              background: url('https://hono.dev/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>
    </>
  )
}

L'environnement d'exécution hono/jsx/dom ​

Un petit environnement d'exécution JSX est disponible pour les composants côté client. Il produit des fichiers regroupés plus petits que hono/jsx. Précisez hono/jsx/dom dans tsconfig.json. Avec Deno, modifiez deno.json.

json
{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "hono/jsx/dom"
  }
}

Vous pouvez aussi préciser hono/jsx/dom dans les options de transformation esbuild de vite.config.ts.

ts
import { defineConfig } from 'vite'

export default defineConfig({
  esbuild: {
    jsxImportSource: 'hono/jsx/dom',
  },
})

Publié sous licence MIT.