renderToNative method
Render a node to native UI
Implementation
Future<String?> renderToNative(DCFComponentNode node,
{String? parentViewId, int? index}) async {
await isReady;
try {
// Handle Fragment nodes
if (node is DCFFragment) {
// Mount the fragment
if (!node.isMounted) {
node.mount(node.parent);
}
// Check if this fragment is a portal placeholder
if (node.metadata != null && node.metadata!['isPortalPlaceholder'] == true) {
// This is a portal placeholder fragment - handle portal logic
final targetId = node.metadata!['targetId'] as String?;
final portalId = node.metadata!['portalId'] as String?;
if (targetId != null && portalId != null) {
// Portal placeholder fragments don't render anything here
// The portal manager handles rendering the children to the target
if (kDebugMode) {
print('🎯 VDom: Portal placeholder fragment for target: $targetId');
}
return null; // Portal placeholders have no native view
}
}
// Regular fragment - render children directly to parent
int childIndex = index ?? 0;
final childIds = <String>[];
for (final child in node.children) {
final childId = await renderToNative(
child,
parentViewId: parentViewId,
index: childIndex++,
);
if (childId != null && childId.isNotEmpty) {
childIds.add(childId);
}
}
// Store child IDs for cleanup later
node.childViewIds = childIds;
return null; // Fragments don't have their own native view ID
}
// Handle Component nodes
if (node is StatefulComponent || node is StatelessComponent) {
try {
// Register the component
registerComponent(node);
// Get the rendered content
final renderedNode = node.renderedNode;
if (renderedNode == null) {
throw Exception('Component rendered null');
}
// Set parent relationship
renderedNode.parent = node;
// Render the content
final viewId = await renderToNative(renderedNode, parentViewId: parentViewId, index: index);
// Store the view ID
node.contentViewId = viewId;
// Call lifecycle method if not already mounted
if (node is StatefulComponent && !node.isMounted) {
node.componentDidMount();
} else if (node is StatelessComponent && !node.isMounted) {
node.componentDidMount();
}
// Run effects for stateful components
if (node is StatefulComponent) {
node.runEffectsAfterRender();
}
return viewId;
} catch (error, stackTrace) {
// Try to find nearest error boundary
final errorBoundary = _findNearestErrorBoundary(node);
if (errorBoundary != null) {
errorBoundary.handleError(error, stackTrace);
return null; // Error handled by boundary
}
// No error boundary, propagate error
rethrow;
}
}
// Handle Element nodes
else if (node is DCFElement) {
return await _renderElementToNative(node, parentViewId: parentViewId, index: index);
}
// Handle EmptyVDomNode
else if (node is EmptyVDomNode) {
return null; // Empty nodes don't create native views
}
return null;
} catch (e, stack) {
if (kDebugMode) {
developer.log('Error rendering node: $e',
name: 'VDom', error: e, stackTrace: stack);
}
return null;
}
}