npx claudepluginhub 15195999826/lomomarketplace --plugin UE_ReactUMGWant just this skill?
Then install: npx claudepluginhub u/[userId]/[slug]
ReactUMG 架构原理深度解析。仅供 PlanReactUMG 和 DebugReactUMG Agent 显式调用,不应在日常开发中直接激活。包含三层架构、Reconciler、hostConfig 等底层实现机制。
This skill uses the workspace's default tool permissions.
ReactUMG 架构原理深度解析
本文档详细说明 ReactUMG 插件如何将 TypeScript 编写的 React 组件转换为 UE5 的 UMG Widget。
1. 核心思想
ReactUMG = React Reconciler + Puerts + UMG
ReactUMG 是一个桥接层,让开发者可以使用 React 的方式编写 UE5 UI,同时保持原生性能和完整类型安全。
关键特性
- ✅ 完全拥抱 React 生态 - 标准 react-reconciler,支持 Hooks、Context、Ref
- ✅ 零性能开销 - Puerts 直接操作 C++ 内存,无序列化/反序列化
- ✅ 极简 C++ 层 - 只有 2 个类 + 5 个函数
- ✅ 完整类型安全 - 2406 行类型定义
- ✅ 自动事件管理 - 自动检测 Delegate 类型,自动绑定/清理
2. 三层架构
┌─────────────────────────────────────────────────────────┐
│ 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) │
└─────────────────────────────────────────────────────────┘
各层职责
TypeScript Layer(开发者层)
- 职责:提供 React 开发体验
- 工具:React 组件、JSX、Hooks、State 管理
- 入口:
ReactUMG.render(<MyComponent />)
React-Reconciler Layer(协调层)
- 职责:将 React VDOM 映射到 UMG Widget 树
- 核心:
hostConfig定义 Widget 操作,UEWidget包装原生 Widget - 优势:使用标准 react-reconciler,兼容 React 生态
C++ Layer(原生层)
- 职责:提供最小化的容器和工具函数
- 设计:极简设计,只有 2 个类
- 集成:与 UE5 UMG 系统无缝对接
3. 核心组件详解
C++ 层组件
UReactWidget(根容器)
文件位置:Plugins/ReactUMG/Source/ReactUMG/ReactWidget.h/.cpp
职责:
- 继承
UUserWidget,作为整个 React UI 的根容器 - 单根限制:只允许一个 RootSlot,对应 React 的单根要求
- 持有
WidgetTree,管理整个 Widget 树 - 提供
AddChild/RemoveChild供 TypeScript 调用
UUMGManager(工具函数库)
文件位置:Plugins/ReactUMG/Source/ReactUMG/UMGManager.h/.cpp
职责:
- 蓝图函数库,暴露静态函数给 TypeScript 调用
CreateReactWidget():创建 UReactWidget 实例SynchronizeWidgetProperties():同步 Widget 属性到 Slate 层SynchronizeSlotProperties():同步 Slot 属性到 Slate 层
为什么需要 Synchronize?
UE5 的 UMG 是双层架构:
- UWidget(逻辑层)- C++ 对象,存储属性
- SWidget(Slate 渲染层)- 实际渲染的组件
当通过 TypeScript 修改 UWidget 的属性时:
- 使用
puerts.merge直接修改 C++ 对象的内存 - UWidget 的属性值已改变,但 SWidget 还未更新
- 必须调用
SynchronizeProperties()将改动同步到 Slate 层
TypeScript 层组件
UEWidget(Widget 包装类)
文件位置:Plugins/ReactUMG/TypeScript/react-umg/react-umg.ts:35-159
职责:
- 包装 UE::Widget,提供统一的操作接口
- 管理属性设置、事件绑定、子节点操作
- 处理 Slot 延迟设置(Slot 由父容器创建)
- 自动清理事件监听,防止内存泄漏
UEWidgetRoot(根容器包装)
文件位置:Plugins/ReactUMG/TypeScript/react-umg/react-umg.ts:161-192
职责:
- 包装
UReactWidget,提供 TypeScript 访问接口 - 管理根 Widget 的添加/移除
- 控制 Widget 在视口中的显示/隐藏
hostConfig(React Reconciler 配置)
文件位置:Plugins/ReactUMG/TypeScript/react-umg/react-umg.ts:195-283
职责:
- 定义 React Reconciler 如何操作 Widget 树
- 处理 Widget 的创建、更新、删除、挂载
- 连接 React VDOM 和 UMG Widget 树
4. 完整更新流程
渲染流程(TypeScript → UMG)
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)
更新流程(Props 变化)
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 层重新渲染
事件流(UMG → TypeScript)
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
5. 完整更新流程(4 阶段)
阶段 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 前
• 私有成员变量的改变永远不会触发任何更新
6. 关键技术点
puerts.merge - 高性能属性设置
优势:
- 减少 JS ↔ C++ 跨界调用次数
- 支持嵌套对象深度合并
- Puerts 内部优化,性能接近原生
SynchronizeProperties - 双层架构同步
为什么需要同步?
- TypeScript 通过
puerts.merge修改 UWidget 属性 - Slate 层的 SWidget 不会自动更新
- 必须调用
SynchronizeProperties()触发同步
Slot 延迟设置
关键点:
- Slot 属性在
init()时暂存,不立即应用 - 父容器
AddChild()后设置nativeSlot,触发 setter - Setter 中应用 Slot 配置并同步
事件自动绑定与清理
避免内存泄漏:
- 每次绑定事件时,存储对应的清理函数
- Widget 销毁时,自动调用所有清理函数
- 防止 C++ Delegate 持有已销毁的 JS 函数引用
lazyloadComponents - 自定义 Widget 支持
使用场景:
- 复杂的自定义 UI 组件(在 UE 编辑器中设计)
- 动画蓝图驱动的 Widget
- 复用 Blueprint 团队的成果
7. 设计亮点
极简 C++ 层
统计:
- 2 个类:UReactWidget, UUMGManager
- 5 个函数:CreateReactWidget, AddChild, RemoveChild, SynchronizeWidgetProperties, SynchronizeSlotProperties
- 总代码量:< 150 行
零性能开销
无序列化/反序列化:
- Puerts 直接修改 C++ 对象内存,接近原生性能
- 一次
puerts.merge设置多个属性,减少跨界调用
完整类型安全
类型定义文件:Typing/react-umg/index.d.ts(2406 行)
覆盖范围:
- ✅ 所有 UMG 组件的 Props 接口
- ✅ 所有 Slot 类型的属性接口
- ✅ UE 类型的 TypeScript 映射
- ✅ 事件回调的参数类型
完全拥抱 React 生态
支持所有 React 特性:
- ✅ Hooks:
useState,useEffect,useContext,useRef等 - ✅ Context API:跨组件共享状态
- ✅ Ref:访问 Widget 实例
- ✅ Fragment:
<></> - ✅ 条件渲染:
{condition && <Widget />} - ✅ 列表渲染:
{items.map(item => <Widget key={item.id} />)}
自动事件管理
bind()时存储清理函数unbindAll()在 Widget 销毁时自动调用- 防止 C++ Delegate 持有悬挂指针
8. 关键源码文件
ReactUMG 插件
C++ 层:
Plugins/ReactUMG/Source/ReactUMG/ReactWidget.h/.cppPlugins/ReactUMG/Source/ReactUMG/UMGManager.h/.cpp
TypeScript 层:
Plugins/ReactUMG/TypeScript/react-umg/react-umg.ts
类型定义
Typing/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/- 运营界面(完整示例)
9. UE 开发者理解指南
render() 不是 CreateWidget()
// ⚠️ UE 开发者常见误解
render() {
return (
<CanvasPanel> // ← 不是每次都创建新的!
<DragPreview /> // ← React 会检查 key 决定复用还是重建
</CanvasPanel>
);
}
// React 的实际行为:
// 第一次 render → 创建 CanvasPanel、创建 DragPreview
// 第二次 render → CanvasPanel 无变化则复用,DragPreview 检查 key
// - key 相同 → 复用,只更新 props
// - key 不同 → 销毁旧的,创建新的
React vs UE 更新模式对比
| 概念 | UE (C++) | React (TypeScript) |
|---|---|---|
| 创建组件 | CreateWidget<T>() 真的创建 | <Component /> 只是描述 |
| 更新位置 | Widget->SetPosition() | <Component Slot={{...}} /> |
| 组件复用 | 手动管理,同一个指针 | React 自动,key 相同则复用 |
| 强制重建 | RemoveChild + CreateWidget | 改变 key |
| 每帧更新 | NativeTick() | setState() → render() |
10. 总结
ReactUMG 通过极简的 C++ 层和完整的 TypeScript 协调层,成功实现了 React 到 UMG 的无缝桥接:
- 三层架构清晰:开发者层(React)→ 协调层(Reconciler)→ 原生层(UMG)
- 核心组件职责明确:UReactWidget(容器)、UUMGManager(工具)、UEWidget(包装)、hostConfig(协调)
- 数据流完整:渲染、更新、事件流程清晰可追溯
- 关键技术精妙:puerts.merge、SynchronizeProperties、Slot 延迟、事件自动管理
- 设计理念先进:极简 C++、零开销、类型安全、拥抱生态
这种架构让开发者可以用 React 的方式编写 UE5 UI,同时保持原生性能和完整类型安全!
Version: v1.0 Last Updated: 2025-12-23
Similar Skills
Expert guidance for Next.js Cache Components and Partial Prerendering (PPR). **PROACTIVE ACTIVATION**: Use this skill automatically when working in Next.js projects that have `cacheComponents: true` in their next.config.ts/next.config.js. When this config is detected, proactively apply Cache Components patterns and best practices to all React Server Component implementations. **DETECTION**: At the start of a session in a Next.js project, check for `cacheComponents: true` in next.config. If enabled, this skill's patterns should guide all component authoring, data fetching, and caching decisions. **USE CASES**: Implementing 'use cache' directive, configuring cache lifetimes with cacheLife(), tagging cached data with cacheTag(), invalidating caches with updateTag()/revalidateTag(), optimizing static vs dynamic content boundaries, debugging cache issues, and reviewing Cache Component implementations.
Applies Anthropic's official brand colors and typography to any sort of artifact that may benefit from having Anthropic's look-and-feel. Use it when brand colors or style guidelines, visual formatting, or company design standards apply.
Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.