Saltar al contenido principal
Los componentes de React son una forma poderosa de crear elementos interactivos y reutilizables en tu documentación.

Uso de componentes de React

Puedes construir componentes de React directamente en tus archivos MDX con React hooks.

Ejemplo

Este ejemplo declara un componente Counter y luego lo utiliza con <Counter />.
export const Counter = () => {
  const [count, setCount] = useState(0)

  const increment = () => setCount(count + 1)
  const decrement = () => setCount(count - 1)

  return (
  <div className="flex items-center justify-center">
      <div className="flex items-center rounded-xl overflow-hidden border border-zinc-950/20 dark:border-white/20">
        <button
          onClick={decrement}
          className="flex items-center justify-center h-8 w-8 text-zinc-950/80 dark:text-white/80 border-r border-zinc-950/20 dark:border-white/20"
          aria-label="Disminuir"
        >
          -
        </button>

        <div className="flex text-sm items-center justify-center h-8 px-6 text-zinc-950/80 dark:text-white/80 font-medium min-w-[4rem] text-center">
          {count}
        </div>

        <button
          onClick={increment}
          className="flex items-center justify-center h-8 w-8 text-zinc-950/80 dark:text-white/80 border-l border-zinc-950/20 dark:border-white/20"
          aria-label="Aumentar"
        >
          +
        </button>
      </div>
    </div>
  )
}

<Counter />
El contador se representa como un componente interactivo de React.

Importar componentes

Para importar componentes de React en tus archivos MDX, los archivos de los componentes deben estar en la carpeta snippets. Luego puedes importarlos en cualquier página MDX de tu documentación. Más información en fragmentos reutilizables.

Ejemplo

Este ejemplo declara un componente ColorGenerator que utiliza varios hooks de React y luego lo emplea en un archivo MDX. Crea el archivo color-generator.jsx en la carpeta snippets:
/snippets/color-generator.jsx
export const ColorGenerator = () => {
  const [hue, setHue] = useState(180)
  const [saturation, setSaturation] = useState(50)
  const [lightness, setLightness] = useState(50)
  const [colors, setColors] = useState([])

  useEffect(() => {
    const newColors = []
    for (let i = 0; i < 5; i++) {
      const l = Math.max(10, Math.min(90, lightness - 20 + i * 10))
      newColors.push(`hsl(${hue}, ${saturation}%, ${l}%)`)
    }
    setColors(newColors)
  }, [hue, saturation, lightness])

  const copyToClipboard = (color) => {
    navigator.clipboard
      .writeText(color)
      .then(() => {
        console.log(`${color} copiado al portapapeles`)
      })
      .catch((err) => {
        console.error("Error al copiar: ", err)
      })
  }

  return (
    <div className="p-4 border dark:border-zinc-950/80 rounded-xl not-prose">
      <div className="space-y-4">
        <div className="space-y-2">
          <label className="block text-sm text-zinc-950/70 dark:text-white/70">
            Tono: {hue}°
            <input
              type="range"
              min="0"
              max="360"
              value={hue}
              onChange={(e) => setHue(Number.parseInt(e.target.value))}
              className="w-full h-2 bg-zinc-950/20 rounded-lg appearance-none cursor-pointer dark:bg-white/20 mt-1"
              style={{
                background: `linear-gradient(to right, 
                  hsl(0, ${saturation}%, ${lightness}%), 
                  hsl(60, ${saturation}%, ${lightness}%), 
                  hsl(120, ${saturation}%, ${lightness}%), 
                  hsl(180, ${saturation}%, ${lightness}%), 
                  hsl(240, ${saturation}%, ${lightness}%), 
                  hsl(300, ${saturation}%, ${lightness}%), 
                  hsl(360, ${saturation}%, ${lightness}%))`,
              }}
            />
          </label>

          <label className="block text-sm text-zinc-950/70 dark:text-white/70">
            Saturación: {saturation}%
            <input
              type="range"
              min="0"
              max="100"
              value={saturation}
              onChange={(e) => setSaturation(Number.parseInt(e.target.value))}
              className="w-full h-2 bg-zinc-950/20 rounded-lg appearance-none cursor-pointer dark:bg-white/20 mt-1"
              style={{
                background: `linear-gradient(to right, 
                  hsl(${hue}, 0%, ${lightness}%), 
                  hsl(${hue}, 50%, ${lightness}%), 
                  hsl(${hue}, 100%, ${lightness}%))`,
              }}
            />
          </label>

          <label className="block text-sm text-zinc-950/70 dark:text-white/70">
            Luminosidad: {lightness}%
            <input
              type="range"
              min="0"
              max="100"
              value={lightness}
              onChange={(e) => setLightness(Number.parseInt(e.target.value))}
              className="w-full h-2 bg-zinc-950/20 rounded-lg appearance-none cursor-pointer dark:bg-white/20 mt-1"
              style={{
                background: `linear-gradient(to right, 
                  hsl(${hue}, ${saturation}%, 0%), 
                  hsl(${hue}, ${saturation}%, 50%), 
                  hsl(${hue}, ${saturation}%, 100%))`,
              }}
            />
          </label>
        </div>

        <div className="flex space-x-1">
          {colors.map((color, idx) => (
            <div
              key={idx}
              className="h-16 rounded flex-1 cursor-pointer transition-transform hover:scale-105"
              style={{ backgroundColor: color }}
              title={`Clic para copiar: ${color}`}
              onClick={() => copyToClipboard(color)}
            />
          ))}
        </div>

        <div className="text-sm font-mono text-zinc-950/70 dark:text-white/70">
          <p>
            Color base: hsl({hue}, {saturation}%, {lightness}%)
          </p>
        </div>
      </div>
    </div>
  )
}
Importa el componente ColorGenerator y úsalo en un archivo MDX:
import { ColorGenerator } from "/snippets/color-generator.jsx"

<ColorGenerator />
El generador de colores se renderiza como un componente interactivo de React.

Consideraciones

Los componentes que usan hooks de React se renderizan en el cliente, lo que tiene varias implicaciones:
  • SEO: Es posible que los motores de búsqueda no indexen por completo el contenido dinámico.
  • Carga inicial: Los visitantes pueden ver un parpadeo de contenido de carga antes de que se rendericen los componentes.
  • Accesibilidad: Asegúrate de que los cambios en el contenido dinámico se anuncien a los lectores de pantalla.
  • Optimiza los arrays de dependencias: Incluye solo las dependencias necesarias en tus arrays de dependencias de useEffect.
  • Memoriza cálculos complejos: Usa useMemo o useCallback para operaciones costosas.
  • Reduce los re-renderizados: Divide los componentes grandes en otros más pequeños para evitar re-renderizados en cascada.
  • Carga diferida (lazy loading): Considera cargar de forma diferida los componentes complejos para mejorar el tiempo de carga inicial de la página.