React: Más hooks explicados


React en su versión 18 introdujo nuevos hooks, no incluídos en el anterior artículo React: Hooks explicados, que serán explicados aquí:

State Hooks

useFormStatus

Este hook permite interactuar con los estados de los formularios. Permite realizar un seguimiento del estado de los envíos como pending, submitted, error, lo que facilita su gestión en aplicaciones React modernas, especialmente con renderizado concurrente.

MyForm.jsx

import { useFormStatus, useState } from 'react'

export const MyForm = ({ submit }) => {
  const { pending, formStatus, setFormStatus } = useFormStatus()
  const [email, setEmail] = useState('')
  const [error, setError] = useState(null)
  const isPending = formStatus === 'pending'
  const isError = formStatus === 'error'

  const handleSubmit = async (event) => {
    event.preventDefault()
    setFormStatus('pending')
    try {
      await submit(email)
      setFormStatus('submitted')
    } catch () {
      setFormStatus('error')
      setError('Submission error. Please try again.')
    }
  }

  return (
    <div>
      <h1>My Form</h1>      
      <form onSubmit={handleSubmit}>
        <input
          type="email"
          value={email}
          onChange={(event) => setEmail(event.target.value)}
          required
        />
        <button type="submit" disabled={isPending}>
          {isPending ? 'Submitting...' : 'Submit'}
        </button>
        {isError && <p>{error}</p>}
      </form>
    </div>
  )
}

Effect Hooks

useInsertionEffect

Este hook permite ejecutar efectos secundarios sincrónicamente, antes de que las mutaciones se confirmen en el DOM. Es útil cuando se necesita insertar algo en el DOM, como añadir una hoja de estilos, antes de que React renderice la página. Forma parte de la API de bajo nivel para gestionar las mutaciones del DOM de forma segura.

DynamicStylesheet.jsx

import { useInsertionEffect } from 'react'
import { theme } from '@/config'

export const DynamicStylesheet = () => {  
  useInsertionEffect(() => {
    const styleElement = document.createElement('style')
    styleElement.innerHTML = `
      body {
        background-color: ${theme === 'dark' ? '#333' : '#FFF'}
        color: ${theme === 'dark' ? '#FFF' : '#000'}
      }
    `
    document.head.appendChild(styleElement)
    
    return () => {
      document.head.removeChild(styleElement)
    }
  }, [theme])
  
  return <div>Content with dynamic styles based on theme</div>
}

Hooks para bibliotecas de terceros

useSyncExternalStore

Este hook permite suscribirse a stores externos o estados fuera de React, lo que garantiza la consistencia al usar renderizado concurrente. Está diseñado para funcionar correctamente con bibliotecas como Redux, Zustand o cualquier otra implementación de store personalizada.

store.js

import create from 'zustand'

export const useStore = create((set) => ({
  count: 0,
  decrease: () => set((state) => ({ count: state.count - 1 })),
  increase: () => set((state) => ({ count: state.count + 1 })),
}))

Counter.jsx

import { useSyncExternalStore } from 'react'
import { useStore } from '@/store'

export const Counter = () => {
  const [count, decrease, increase] = useStore((state) => [
    state.count,
    state.decrease,
    state.increase
  ])
  const syncCount = useSyncExternalStore(
    useStore.subscribe,
    () => count,
    () => count
  )

  return (
    <div>
      <h1>Count: {syncCount}</h1>
      <button onClick={decrease}>Decrease</button>
      <button onClick={increase}>Increase</button>
    </div>
  )
}

Estos hooks proporcionan una forma más controlada de interactuar con el ciclo de vida y el estado externo de React, lo que facilita la gestión de aplicaciones complejas y concurrentes.

2025-08-17
Escrito por Samuel de Vega.
Etiquetas