Adapter de React
El adapter de React es el más completo de los trece: es el único que soporta
a la vez props vivas (update) e hidratación SSR (hydrate).
npm install wu-framework react react-dom// src/main.jsx — la micro-appimport { wuReact } from 'wu-framework/adapters/react';import App from './App';
wuReact.register('cart', App);Esa es toda la integración. Levanta el servidor de desarrollo por su cuenta y
la app se monta en #root en modo standalone; cárgala desde un shell y se
monta en el Shadow DOM del shell.
register(appName, Component, options)
Sección titulada «register(appName, Component, options)»await wuReact.register('cart', CartApp, { props: { currency: 'EUR', locale: 'es-ES' }, strictMode: true, standalone: true, standaloneContainer: '#root', onMount: (container) => console.log('[cart] montado'), onUnmount: (container) => console.log('[cart] desmontando'),});| Opción | Tipo | Por defecto | Notas |
|---|---|---|---|
props |
object |
{} |
Props iniciales. Se fusionan con lo que llegue vía wu.update(). |
strictMode |
boolean |
true |
Envuelve el árbol en React.StrictMode. Aplica tanto al montaje como a la hidratación. |
standalone |
boolean |
true |
Monta directamente cuando no se encuentra un shell. |
standaloneContainer |
string |
'#root' |
Selector usado en modo standalone. |
onMount |
function |
null |
(container) => void, después de montar y después de hidratar. |
onUnmount |
function |
null |
(container) => void, antes de root.unmount(). |
Devuelve Promise<boolean>.
De dónde sale React
Sección titulada «De dónde sale React»ensureReact() resuelve React en este orden:
window.React+window.ReactDOM— el montaje habitual de micro-frontends. Si faltawindow.ReactDOM.createRoot(expusistereact-domen vez dereact-dom/client), importa dinámicamentereact-dom/clientpara obtenercreateRootyhydrateRoot.import('react')+import('react-dom/client')dinámicos.
Si ninguna funciona, register() registra un error y devuelve false.
Props vivas
Sección titulada «Props vivas»El adapter de React anuncia update, así que el shell puede enviar props
nuevas sin remontar:
// En el shellawait wu.update('cart', { currency: 'USD' });Internamente el adapter fusiona las props nuevas sobre las actuales y vuelve a
llamar a root.render() sobre la raíz existente. React reconcilia en el
sitio: el árbol de componentes conserva su estado, los efectos no vuelven a
ejecutar su limpieza y no se tira nada del DOM.
Al desmontar, las props enviadas en vivo se descartan y currentProps vuelve a
las props que pasaste a register(). Esto importa cuando wu-core reubica una
app en otro contenedor: el nuevo montaje parte de las props de registro, no de
lo último que envió el shell.
Hidratación SSR
Sección titulada «Hidratación SSR»Cuando el contenedor lo produjo wu-framework/server, wu-core llama a
hydrate en lugar de mount, pasando exactamente las props con las que
renderizó el servidor:
// Las props del servidor ganan sobre las de registro: ellas produjeron el markup.wuReact.register('cart', CartApp, { props: { currency: 'EUR' } });// El servidor renderizó con { currency: 'USD' } → la hidratación usa 'USD'.El adapter llama a hydrateRoot(container, element) sin vaciar el
contenedor: vaciarlo destruiría justamente el markup que se está hidratando.
Dos planes B mantienen esto seguro:
- No hay
hydrateRootdisponible (React < 18, o un bundle sinreact-dom/client) → avisa y monta normalmente. Correcto, solo que repintado. - La hidratación lanza (desajuste de markup) → registra el error y monta normalmente. Un desajuste nunca debe dejar la app sin montar.
Consulta Hidratación para el lado del servidor.
StrictMode
Sección titulada «StrictMode»strictMode vale true por defecto. En desarrollo, React montará, desmontará
y volverá a montar tu componente; el adapter no intenta suprimir eso. La
protección contra la doble invocación de StrictMode a nivel de Wu (desmontaje
diferido) vive en wu-core, no en el adapter.
Pon strictMode: false si alguna dependencia de terceros de tu árbol se porta
mal bajo doble invocación.
Helpers del lado del shell
Sección titulada «Helpers del lado del shell»El adapter de React exporta factorías, no componentes. Le pasas tu propio
namespace React para que el adapter nunca tenga que resolver una segunda
copia de React, lo que rompería los hooks.
createWuSlot(React)
Sección titulada «createWuSlot(React)»import React from 'react';import { createWuSlot } from 'wu-framework/adapters/react';
const WuSlot = createWuSlot(React);
export default function Shell() { return ( <main> <WuSlot name="cart" url="http://localhost:3001" /> <WuSlot name="checkout" url="http://localhost:3002" fallback={<Spinner />} onLoad={({ name }) => console.log(name, 'cargado')} onError={(err) => report(err)} /> </main> );}| Prop | Tipo | Notas |
|---|---|---|
name |
string |
Nombre de la micro-app. También se usa para el id del contenedor. |
url |
string |
URL de la app (se guarda como data-wu-url). |
appName |
string |
Sustituye a name cuando el id del DOM y el nombre de la app deben diferir. |
fallback |
ReactNode |
Reemplaza el elemento “Loading…” por defecto. |
onLoad |
function |
({ name, url }) => void |
onError |
function |
(err) => void |
onMount |
function |
({ name, container }) => void |
onUnmount |
function |
({ name }) => void |
className, style |
Se aplican al elemento del slot. |
Dos detalles de implementación que conviene conocer, porque explican la forma del DOM renderizado:
- El
divde destino tiene un id estable derivado del nombre de la app (wu-slot-<appName>) y está presente desde el primer render, así quewu.mount(name, '#id')lo encuentra sin ningúnappendChildimperativo. - El fallback y el destino de montaje son hermanos dentro de un Fragment,
nunca padre e hijo.
wu.mountcrea una segunda raíz de React dentro del destino; si React también gestionara hijos ahí, desmontar el fallback llamaría aremoveChildsobre nodos que la micro-app ya reemplazó —"The node to be removed is not a child of this node".
El efecto de montaje es seguro con StrictMode: un timeout de 50 ms más un flag
cancelled hacen que el primer ciclo (descartado) de StrictMode se cancele
antes de llegar a montar.
createUseWuEvents(React)
Sección titulada «createUseWuEvents(React)»import React from 'react';import { createUseWuEvents } from 'wu-framework/adapters/react';
const useWuEvents = createUseWuEvents(React);
function Cart() { const { emit, on, once } = useWuEvents();
React.useEffect(() => on('user:login', (e) => setUser(e.data)), [on]);
return <button onClick={() => emit('cart:add', { sku: 'A1' })}>Añadir</button>;}on() devuelve una función para cancelar la suscripción y la registra
internamente, así que toda suscripción se cierra cuando el componente se
desmonta; devolverla desde el efecto, como arriba, es doble seguridad.
createUseWuStore(React)
Sección titulada «createUseWuStore(React)»const useWuStore = createUseWuStore(React);
function Profile() { const { state, setState, getState } = useWuStore('user');
return ( <input value={state?.name ?? ''} onChange={(e) => setState('name', e.target.value)} /> );}setState(path, value) escribe en <namespace>.<path>. La suscripción es
sobre la propia ruta del namespace, lo que captura tanto escrituras en la raíz
(set('user', {...})) como escrituras profundas
(set('user.profile.name', x)) gracias a la notificación por rutas padre del
store.
createUseWuAI(React)
Sección titulada «createUseWuAI(React)»const useWuAI = createUseWuAI(React);
function Assistant() { const { messages, send, isStreaming, error, abort, clear } = useWuAI({ namespace: 'support', onActionExecuted: (data) => console.log('la IA ejecutó', data.action), });
return ( <> {messages.map((m) => <Bubble key={m.id} role={m.role} text={m.content} />)} <button onClick={() => send('Muéstrame los pedidos pendientes')} disabled={isStreaming}> Preguntar </button> {isStreaming && <button onClick={abort}>Parar</button>} </> );}Este es el hook de IA más rico de los trece adapters: el único con streaming
real de tokens. send() itera wu.ai.stream() y va añadiendo los fragmentos de
texto a un mensaje provisional del asistente conforme llegan; sendSync()
espera la respuesta completa en su lugar. Los mensajes con role: 'action' se
inyectan automáticamente cuando la IA ejecuta una acción, disparados por el
evento ai:action:executed.
Consulta Visión general de IA para el modelo de orquestación.
Exports
Sección titulada «Exports»import { wuReact, // export por defecto, y el objeto que contiene todo lo de abajo register, createWuSlot, createUseWuEvents, createUseWuStore, createUseWuAI, getWuInstance, waitForWu,} from 'wu-framework/adapters/react';Desde el barrel (wu-framework/adapters), register se re-exporta como
registerReact.
