rehydrate.rs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. use crate::dom::WebsysDom;
  2. use dioxus_core::AttributeValue;
  3. use dioxus_core::{DynamicNode, ElementId, ScopeState, TemplateNode, VNode, VirtualDom};
  4. #[derive(Debug)]
  5. pub enum RehydrationError {
  6. VNodeNotInitialized,
  7. }
  8. use RehydrationError::*;
  9. impl WebsysDom {
  10. // we're streaming in patches, but the nodes already exist
  11. // so we're just going to write the correct IDs to the node and load them in
  12. pub fn rehydrate(&mut self, dom: &VirtualDom) -> Result<(), RehydrationError> {
  13. let root_scope = dom.base_scope();
  14. let mut ids = Vec::new();
  15. let mut to_mount = Vec::new();
  16. // Recursively rehydrate the dom from the VirtualDom
  17. self.rehydrate_scope(root_scope, dom, &mut ids, &mut to_mount)?;
  18. dioxus_interpreter_js::hydrate(ids);
  19. for id in to_mount {
  20. self.send_mount_event(id);
  21. }
  22. Ok(())
  23. }
  24. fn rehydrate_scope(
  25. &mut self,
  26. scope: &ScopeState,
  27. dom: &VirtualDom,
  28. ids: &mut Vec<u32>,
  29. to_mount: &mut Vec<ElementId>,
  30. ) -> Result<(), RehydrationError> {
  31. let vnode = scope.root_node();
  32. self.rehydrate_vnode(dom, vnode, ids, to_mount)
  33. }
  34. fn rehydrate_vnode(
  35. &mut self,
  36. dom: &VirtualDom,
  37. vnode: &VNode,
  38. ids: &mut Vec<u32>,
  39. to_mount: &mut Vec<ElementId>,
  40. ) -> Result<(), RehydrationError> {
  41. for (i, root) in vnode.template.get().roots.iter().enumerate() {
  42. self.rehydrate_template_node(
  43. dom,
  44. vnode,
  45. root,
  46. ids,
  47. to_mount,
  48. Some(vnode.mounted_root(i, dom).ok_or(VNodeNotInitialized)?),
  49. )?;
  50. }
  51. Ok(())
  52. }
  53. fn rehydrate_template_node(
  54. &mut self,
  55. dom: &VirtualDom,
  56. vnode: &VNode,
  57. node: &TemplateNode,
  58. ids: &mut Vec<u32>,
  59. to_mount: &mut Vec<ElementId>,
  60. root_id: Option<ElementId>,
  61. ) -> Result<(), RehydrationError> {
  62. tracing::trace!("rehydrate template node: {:?}", node);
  63. match node {
  64. TemplateNode::Element {
  65. children, attrs, ..
  66. } => {
  67. let mut mounted_id = root_id;
  68. for attr in *attrs {
  69. if let dioxus_core::TemplateAttribute::Dynamic { id } = attr {
  70. let attributes = &*vnode.dynamic_attrs[*id];
  71. let id = vnode
  72. .mounted_dynamic_attribute(*id, dom)
  73. .ok_or(VNodeNotInitialized)?;
  74. for attribute in attributes {
  75. let value = &attribute.value;
  76. mounted_id = Some(id);
  77. if let AttributeValue::Listener(_) = value {
  78. if attribute.name == "onmounted" {
  79. to_mount.push(id);
  80. }
  81. }
  82. }
  83. }
  84. }
  85. if let Some(id) = mounted_id {
  86. ids.push(id.0 as u32);
  87. }
  88. if !children.is_empty() {
  89. for child in *children {
  90. self.rehydrate_template_node(dom, vnode, child, ids, to_mount, None)?;
  91. }
  92. }
  93. }
  94. TemplateNode::Dynamic { id } | TemplateNode::DynamicText { id } => self
  95. .rehydrate_dynamic_node(
  96. dom,
  97. &vnode.dynamic_nodes[*id],
  98. *id,
  99. vnode,
  100. ids,
  101. to_mount,
  102. )?,
  103. _ => {}
  104. }
  105. Ok(())
  106. }
  107. fn rehydrate_dynamic_node(
  108. &mut self,
  109. dom: &VirtualDom,
  110. dynamic: &DynamicNode,
  111. dynamic_node_index: usize,
  112. vnode: &VNode,
  113. ids: &mut Vec<u32>,
  114. to_mount: &mut Vec<ElementId>,
  115. ) -> Result<(), RehydrationError> {
  116. tracing::trace!("rehydrate dynamic node: {:?}", dynamic);
  117. match dynamic {
  118. dioxus_core::DynamicNode::Text(_) | dioxus_core::DynamicNode::Placeholder(_) => {
  119. ids.push(
  120. vnode
  121. .mounted_dynamic_node(dynamic_node_index, dom)
  122. .ok_or(VNodeNotInitialized)?
  123. .0 as u32,
  124. );
  125. }
  126. dioxus_core::DynamicNode::Component(comp) => {
  127. let scope = comp
  128. .mounted_scope(dynamic_node_index, vnode, dom)
  129. .ok_or(VNodeNotInitialized)?;
  130. self.rehydrate_scope(scope, dom, ids, to_mount)?;
  131. }
  132. dioxus_core::DynamicNode::Fragment(fragment) => {
  133. for vnode in fragment {
  134. self.rehydrate_vnode(dom, vnode, ids, to_mount)?;
  135. }
  136. }
  137. }
  138. Ok(())
  139. }
  140. }