ReactUMG 架构原理深度解析。仅供 PlanReactUMG 和 DebugReactUMG Agent 显式调用,不应在日常开发中直接激活。包含三层架构、Reconciler、hostConfig 等底层实现机制。
Provides deep architectural knowledge of ReactUMG, the bridge layer for writing UE5 UMG UIs using React. Claude will use this when debugging ReactUMG issues or planning new ReactUMG features, as it explains the three-layer architecture (TypeScript/Reconciler/C++), core components like UReactWidget and hostConfig, and the complete data flow from React render to UMG display.
/plugin marketplace add 15195999826/LomoMarketplace/plugin install UE_ReactUMG@LomoMarketplaceThis skill inherits all available tools. When active, it can use any tool Claude has access to.
本文档详细说明 ReactUMG 插件如何将 TypeScript 编写的 React 组件转换为 UE5 的 UMG Widget。
ReactUMG = React Reconciler + Puerts + UMG
ReactUMG 是一个桥接层,让开发者可以使用 React 的方式编写 UE5 UI,同时保持原生性能和完整类型安全。
┌─────────────────────────────────────────────────────────┐
│ TypeScript Layer (开发者编写层) │
│ ───────────────────────────────────────────────────── │
│ - 开发者编写 React.Component │
│ - 使用 JSX 语法描述 UI 结构 │
│ - 调用 ReactUMG.render() 渲染 │
│ - 管理状态和业务逻辑 │
└───────────────────────┬─────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ React-Reconciler Layer (协调层,核心逻辑) │
│ ───────────────────────────────────────────────────── │
│ - hostConfig 定义如何操作 Widget │
│ - UEWidget 包装 UE::Widget │
│ - UEWidgetRoot 包装 UReactWidget │
│ - 处理 VDOM diff/update/mount/unmount │
│ - 管理 Widget 树的生命周期 │
└───────────────────────┬─────────────────────────────────┘
│ Puerts Bridge (JS ↔ C++)
▼
┌─────────────────────────────────────────────────────────┐
│ C++ Layer (UE5 原生层) │
│ ───────────────────────────────────────────────────── │
│ - UReactWidget (根容器 UserWidget) │
│ - UUMGManager (蓝图函数库,工具函数) │
│ - UWidget::SynchronizeProperties() (同步到 Slate) │
└─────────────────────────────────────────────────────────┘
ReactUMG.render(<MyComponent />)hostConfig 定义 Widget 操作,UEWidget 包装原生 Widget文件位置:Plugins/ReactUMG/Source/ReactUMG/ReactWidget.h/.cpp
职责:
UUserWidget,作为整个 React UI 的根容器WidgetTree,管理整个 Widget 树AddChild/RemoveChild 供 TypeScript 调用文件位置:Plugins/ReactUMG/Source/ReactUMG/UMGManager.h/.cpp
职责:
CreateReactWidget():创建 UReactWidget 实例SynchronizeWidgetProperties():同步 Widget 属性到 Slate 层SynchronizeSlotProperties():同步 Slot 属性到 Slate 层为什么需要 Synchronize?
UE5 的 UMG 是双层架构:
当通过 TypeScript 修改 UWidget 的属性时:
puerts.merge 直接修改 C++ 对象的内存SynchronizeProperties() 将改动同步到 Slate 层文件位置:Plugins/ReactUMG/TypeScript/react-umg/react-umg.ts:35-159
职责:
文件位置:Plugins/ReactUMG/TypeScript/react-umg/react-umg.ts:161-192
职责:
UReactWidget,提供 TypeScript 访问接口文件位置:Plugins/ReactUMG/TypeScript/react-umg/react-umg.ts:195-283
职责:
1. 开发者调用:
ReactUMG.render(<TaleSelectPanel />)
↓
2. React Reconciler 递归处理 VDOM:
hostConfig.createInstance("CanvasPanel", props)
→ new UEWidget("CanvasPanel", props)
→ new UE.CanvasPanel()
↓
3. 构建 Widget 树结构:
hostConfig.appendInitialChild(parent, child)
→ parent.appendChild(child)
→ parent.nativePtr.AddChild(child.nativePtr)
↓
4. 应用 Widget 属性:
puerts.merge(widget.nativePtr, {Text: "Hello"})
→ 直接修改 C++ 对象属性
↓
5. 同步属性到 Slate 层:
UE.UMGManager.SynchronizeWidgetProperties(...)
→ widget->SynchronizeProperties()
→ Slate 层更新
↓
6. 显示到屏幕:
hostConfig.resetAfterCommit(root)
→ root.addToViewport(0)
1. 状态变化触发:
this.setState({count: 2})
↓
2. Reconciler Diff Props:
hostConfig.prepareUpdate(...)
→ !deepEquals(...) → return true
↓
3. 提交更新:
hostConfig.commitUpdate(instance, ...)
→ instance.update(oldProps, newProps)
→ puerts.merge(nativePtr, {Text: "2"})
→ UE.UMGManager.SynchronizeWidgetProperties(...)
↓
4. 屏幕更新:
Slate 层重新渲染
1. 初始化时绑定事件:
<Button OnClicked={this.handleClick} />
→ UEWidget.bind("OnClicked", this.handleClick)
→ nativePtr.OnClicked.Add(this.handleClick)
↓
2. 用户交互触发事件:
用户点击按钮
→ UButton::OnClicked.Broadcast()
↓
3. Puerts 桥接转发:
C++ Delegate.Broadcast()
→ Puerts 拦截并转发到 JS
→ this.handleClick() 在 TypeScript 中执行
↓
4. TypeScript 处理事件:
handleClick() { this.setState({clicked: true}) }
→ 触发 Re-render
阶段 0:触发源(用户代码)
├── setState() - 状态更新
├── forceUpdate() - 强制更新
├── Context 变化 - Provider value
└── ReactUMG.render() - 初次挂载
⚠️ 私有成员变量改变不触发任何更新
↓
阶段 1:父组件视角(发起者)
父组件 render()
↓
生成新的 Virtual DOM: <Child propA={newValue} />
↓
Props 流向子组件 (oldProps → newProps)
📌 "Props Change" 是父组件 render 的结果,不是原因
↓
阶段 2:子组件视角(响应者)
Props Changed
↓
shouldComponentUpdate?
├── false → 停止更新
└── true → 子组件 render() → Diff 算法
📌 这就是 "Props Change → SCU → Render"
↓
阶段 3:Commit 阶段(hostConfig)
key/type 变了?
├── 是 → 销毁重建 (removeChild + createInstance + appendChild)
└── 否 → ref 变了?
├── 是 → ref 重绑定 (getPublicInstance)
└── 否 → props 变了?(deepEquals)
├── 是 → 属性更新
│ prepareUpdate() → commitUpdate()
│ puerts.merge(nativePtr, props)
│ SynchronizeWidgetProperties()
└── 否 → 无操作
关键结论:
• React 组件的 Render(生成 VDOM)≠ UE Widget 的 Update(实际修改属性)
• Props Change 发生在两个 Render 之间:父组件 Render 后、子组件 Render 前
• 私有成员变量的改变永远不会触发任何更新
优势:
为什么需要同步?
puerts.merge 修改 UWidget 属性SynchronizeProperties() 触发同步关键点:
init() 时暂存,不立即应用AddChild() 后设置 nativeSlot,触发 setter避免内存泄漏:
使用场景:
统计:
无序列化/反序列化:
puerts.merge 设置多个属性,减少跨界调用类型定义文件:Typing/react-umg/index.d.ts(2406 行)
覆盖范围:
支持所有 React 特性:
useState, useEffect, useContext, useRef 等<></>{condition && <Widget />}{items.map(item => <Widget key={item.id} />)}bind() 时存储清理函数unbindAll() 在 Widget 销毁时自动调用C++ 层:
Plugins/ReactUMG/Source/ReactUMG/ReactWidget.h/.cppPlugins/ReactUMG/Source/ReactUMG/UMGManager.h/.cppTypeScript 层:
Plugins/ReactUMG/TypeScript/react-umg/react-umg.tsTyping/react-umg/index.d.ts(2406 行)- React-UMG 组件类型Typing/ue/index.d.ts - UE5 类型映射TypeScript/src/debug-panel/DebugPanel.tsx - 调试面板(复杂布局)TypeScript/src/tale-select-panel/index.tsx - 剧本选择(居中布局)TypeScript/src/formation-panel/index.tsx - 编队面板(底部布局)TypeScript/src/game-operation-window/ - 运营界面(完整示例)// ⚠️ UE 开发者常见误解
render() {
return (
<CanvasPanel> // ← 不是每次都创建新的!
<DragPreview /> // ← React 会检查 key 决定复用还是重建
</CanvasPanel>
);
}
// React 的实际行为:
// 第一次 render → 创建 CanvasPanel、创建 DragPreview
// 第二次 render → CanvasPanel 无变化则复用,DragPreview 检查 key
// - key 相同 → 复用,只更新 props
// - key 不同 → 销毁旧的,创建新的
| 概念 | UE (C++) | React (TypeScript) |
|---|---|---|
| 创建组件 | CreateWidget<T>() 真的创建 | <Component /> 只是描述 |
| 更新位置 | Widget->SetPosition() | <Component Slot={{...}} /> |
| 组件复用 | 手动管理,同一个指针 | React 自动,key 相同则复用 |
| 强制重建 | RemoveChild + CreateWidget | 改变 key |
| 每帧更新 | NativeTick() | setState() → render() |
ReactUMG 通过极简的 C++ 层和完整的 TypeScript 协调层,成功实现了 React 到 UMG 的无缝桥接:
这种架构让开发者可以用 React 的方式编写 UE5 UI,同时保持原生性能和完整类型安全!
Version: v1.0 Last Updated: 2025-12-23
This skill should be used when the user asks to "create a hookify rule", "write a hook rule", "configure hookify", "add a hookify rule", or needs guidance on hookify rule syntax and patterns.
Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.