Como consumir wp.data select y dispatch en bloques (JS) en WordPress

Contents

Introducción

En Gutenberg y en cualquier desarrollo con bloques para WordPress moderno, la librería wp.data es la forma recomendada para leer estado (select) y disparar acciones (dispatch) en los distintos stores del editor. Este artículo explica con todo detalle cómo consumir wp.data —tanto mediante las APIs React hooks (useSelect / useDispatch) como mediante la API global select/dispatch/subscribe— y muestra ejemplos prácticos para bloques JS, patrones seguros y buenas prácticas para evitar problemas de rendimiento o bucles infinitos.

Conceptos clave

  • Stores: wp.data organiza estado en stores con nombres como core, core/editor, core/block-editor, core/block-editor o stores personalizados que registres.
  • select(storeName): permite leer el estado (selectors). Devuelve datos de forma síncrona algunos selectors pueden estar pendientes de resolución (resolvers) y devolver undefined hasta que los datos lleguen.
  • dispatch(storeName): dispara acciones (actions) que mutan el estado o ejecutan operaciones asíncronas.
  • Hooks React: useSelect y useDispatch (importados desde @wordpress/data) son la forma idiomática para leer y mutar estado dentro de componentes de bloque / editor. Manejan la suscripción y re-render automáticamente.
  • subscribe: permite suscribirse a cambios globales del store registry útil en scripts fuera de React o para orquestar reactividad más fina.

Cuándo usar useSelect / useDispatch vs select / dispatch

  • useSelect / useDispatch: en componentes React (por ejemplo, la función edit de un bloque). Evitan manejo manual de suscripciones y re-renderizan el componente cuando cambia el selector usado.
  • select / dispatch / subscribe: en scripts fuera de React, en funciones globales o cuando no exista un árbol React. También útil para testing o utilidades que se ejecutan fuera de la renderización de un componente.

Regla importante

Nunca llames a un dispatch directamente dentro de la función de renderizado de un componente (ni dentro del callback de useSelect). Si necesitas disparar una acción en respuesta a un cambio de selección, usa useEffect (o un equivalente) para evitar bucles infinitos.

Ejemplos prácticos

1) Ejemplo: leer meta del post y actualizarlo con useSelect useDispatch

Este ejemplo muestra el patrón más común: en la UI de un bloque quieres mostrar y escribir un valor de meta del post. Observa el uso de useSelect para leer y useDispatch para editar el post la actualización se hace en un handler que evita efectos durante la renderización.

// Language: javascript
import { useSelect, useDispatch } from @wordpress/data
import { TextControl, Button } from @wordpress/components
import { useState, useEffect } from @wordpress/element

export default function EditMyMetaBlock() {
  // Lee el meta editado en el editor
  const metaValue = useSelect(
    (select) => select(core/editor).getEditedPostAttribute(meta)?._my_meta  ,
    [] // dependencias: si quieres re-evaluar cuando cambien props/atributos, añádelas aquí
  )

  // Obtén la acción editPost desde core/editor
  const { editPost } = useDispatch(core/editor)

  // Local state para el input para evitar escribir cada tecla directamente al store
  const [localValue, setLocalValue] = useState(metaValue)

  // Mantener localValue sincronizado cuando metaValue cambie desde otro sitio
  useEffect(() => {
    setLocalValue(metaValue)
  }, [metaValue])

  // Handler que aplica el cambio al post (no dentro del render)
  function onApply() {
    editPost({ meta: { _my_meta: localValue } })
  }

  return (
    <>
       setLocalValue(v)}
      />
      
    
  )
}

2) Ejemplo: manipular bloques en el editor (insertar, reemplazar, seleccionar)

Para manipular bloques dentro del editor usamos el store core/block-editor. Aquí se muestra cómo insertar un bloque programáticamente, reemplazar un bloque y seleccionar un bloque.

// Language: javascript
import { useSelect, useDispatch } from @wordpress/data
import { Button } from @wordpress/components
import { createBlock } from @wordpress/blocks

export default function BlockControlsExample() {
  const blocks = useSelect((select) => select(core/block-editor).getBlocks(), [])
  const { insertBlocks, replaceBlocks, selectBlock } = useDispatch(core/block-editor)

  function addParagraph() {
    const paragraphBlock = createBlock(core/paragraph, { content: Bloque insertado programáticamente })
    insertBlocks(paragraphBlock, undefined / index al final /)
  }

  function replaceFirst() {
    if (!blocks.length) return
    const newBlock = createBlock(core/heading, { content: Reemplazo de bloque })
    replaceBlocks(blocks[0].clientId, newBlock)
    // seleccionar el nuevo bloque: selectBlock espera clientId replaceBlocks devuelve clientId?
    // Si necesitas seleccionar explícitamente, obtén después el bloque insertado o usa callbacks/efectos.
  }

  function selectFirst() {
    if (!blocks.length) return
    selectBlock(blocks[0].clientId)
  }

  return (
    <>
      
      
      
    
  )
}

3) Ejemplo: uso de select / dispatch / subscribe fuera de React

Puede que necesites ejecutar lógica desde un archivo JS que no es componente React (por ejemplo, un script cargado en admin). En ese caso usa wp.data.select/dispatch y wp.data.subscribe para escuchar cambios.

// Language: javascript
// Este código asume wp.data disponible globalmente (en el editor)
(function () {
  const { select, dispatch, subscribe } = wp.data

  // Leer título actual
  console.log(Título actual:, select(core/editor).getEditedPostAttribute(title))

  // Escuchar cambios y reaccionar una sola vez
  let lastTitle = select(core/editor).getEditedPostAttribute(title)
  const unsubscribe = subscribe(() =gt {
    const newTitle = select(core/editor).getEditedPostAttribute(title)
    if (newTitle !== lastTitle) {
      lastTitle = newTitle
      console.log(Título cambiado a:, newTitle)
      // Si queremos, disparar acción al cambiar:
      // dispatch(core/editor).editPost({ meta: { _some: value } })
    }
  })

  // Para dejar de escuchar cuando sea necesario:
  // unsubscribe()
})()

4) Patrón con withSelect / withDispatch (HOC) — legado

Si estás manteniendo código que usa HOCs en lugar de hooks, aquí tienes un patrón con withSelect y withDispatch. Funciona bien cuando no puedes usar hooks (por ejemplo, clases).

// Language: javascript
import { withSelect, withDispatch } from @wordpress/data
import { compose } from @wordpress/compose
import { TextControl } from @wordpress/components

function MyBlockEdit(props) {
  const { metaValue, editPostMeta } = props
  return (
    
  )
}

export default compose(
  withSelect((select) =gt {
    return {
      metaValue: select(core/editor).getEditedPostAttribute(meta)?._my_meta  ,
    }
  }),
  withDispatch((dispatch) =gt {
    return {
      editPostMeta: (value) =gt dispatch(core/editor).editPost({ meta: { _my_meta: value } }),
    }
  })
)(MyBlockEdit)

Trucos y detalles avanzados

  • Datos que tardan en resolverse: muchos selectors (por ejemplo, getEntityRecords) dependen de resolvers que realizan peticiones a la REST API. Cuando uses useSelect, el selector puede devolver undefined inicialmente. Trata undefined como loading y renderiza un placeholder o spinner hasta que llegue el dato.
  • Evitar re-renderes innecesarios: pasa una función selector estable a useSelect y limita dependencias. useSelect re-ejecuta cuando cambia la salida del selector. Usa useCallback / useMemo si calculas funciones derivadas costosas.
  • No llamar dispatch durante render: si necesitas actualizar el store cuando la selección cambie, usa useEffect para disparar la acción en respuesta al cambio.
  • Batching: muchas acciones pueden agruparse en una única llamada a editPost cuando sea posible para evitar múltiples renders.
  • Subscripciones: si usas wp.data.subscribe, asegúrate de llamar a unsubscribe cuando ya no necesites la suscripción (por ejemplo, al desmontar un componente o cuando el script finaliza).
  • Store registry: si necesitas trabajar con un store personalizado, regístralo con wp.data.registerStore y utilízalo por su nombre en select/dispatch. El patrón es el mismo.

Ejemplo completo y seguro: leer posts con getEntityRecords y mostrar loading

Aquí un patrón típico para obtener entidad (posts) desde core y manejar la condición de carga:

// Language: javascript
import { useSelect } from @wordpress/data
import { Spinner } from @wordpress/components

export default function MyPostsList() {
  const posts = useSelect(
    (select) =gt select(core).getEntityRecords(postType, post, { per_page: 5 }),
    [] // puedes añadir dependencias si cambias filtros dinámicamente
  )

  if (posts === undefined) {
    // El selector aún se está resolviendo
    return ltSpinner /gt
  }

  if (!posts  posts.length === 0) {
    return ltpgtNo hay posts.lt/pgt
  }

  return (
    ltulgt
      {posts.map((post) =gt (
        ltli key={post.id}gt{post.title.rendered}lt/ligt
      ))}
    lt/ulgt
  )
}

Buenas prácticas resumidas

  1. Usa useSelect/useDispatch dentro de componentes React y select/dispatch fuera de React.
  2. No dispares dispatch dentro del render: usa useEffect para reacciones a cambios.
  3. Maneja selectors que devuelven undefined (loading) con placeholders.
  4. Minimiza los selectores que consumes combinar datos en un solo selector puede reducir re-renderizados.
  5. Usa createBlock y las funciones del store core/block-editor para operaciones sobre bloques (insertBlocks, replaceBlocks, selectBlock, updateBlockAttributes si aplica).
  6. Si trabajas con stores personalizados, registra correctamente resolvers y actions para integrarlo con la arquitectura de wp.data.

Referencias rápidas (APIs comunes)

  • Hooks: useSelect((select) =gt …), useDispatch(storeName)
  • Global: const { select, dispatch, subscribe } = wp.data
  • Stores frecuentes: core, core/editor, core/block-editor, core/block-editor (tareas relacionadas con el editor y bloques)
  • Funciones útiles: select(…).getEditedPostAttribute(meta), select(core/block-editor).getBlocks(), dispatch(core/editor).editPost({…}), dispatch(core/block-editor).insertBlocks(…)

Conclusión

wp.data es una herramienta potente y flexible para interactuar con el estado del editor de WordPress. Usar correctamente select/dispatch y las abstracciones React (useSelect/useDispatch) permite construir bloques robustos y con buen rendimiento. Recuerda manejar estados de carga, evitar dispatchs en render, y optar por patrones que minimicen re-renderizados. Los ejemplos incluidos cubren los casos más habituales: meta del post, manipulación de bloques, uso fuera de React y compatibilidad con HOCs.



Acepto donaciones de BAT's mediante el navegador Brave 🙂



Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *