rehydrate.rs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. use crate::dom::WebsysDom;
  2. use dioxus_core::prelude::*;
  3. use dioxus_core::AttributeValue;
  4. use dioxus_core::WriteMutations;
  5. use dioxus_core::{DynamicNode, ElementId, ScopeState, TemplateNode, VNode, VirtualDom};
  6. use dioxus_interpreter_js::save_template;
  7. #[derive(Debug)]
  8. pub enum RehydrationError {
  9. VNodeNotInitialized,
  10. }
  11. use RehydrationError::*;
  12. impl WebsysDom {
  13. // we're streaming in patches, but the nodes already exist
  14. // so we're just going to write the correct IDs to the node and load them in
  15. pub fn rehydrate(&mut self, dom: &VirtualDom) -> Result<(), RehydrationError> {
  16. let root_scope = dom.base_scope();
  17. let mut ids = Vec::new();
  18. let mut to_mount = Vec::new();
  19. // Recursively rehydrate the dom from the VirtualDom
  20. self.rehydrate_scope(root_scope, dom, &mut ids, &mut to_mount)?;
  21. dioxus_interpreter_js::hydrate(self.interpreter.js_channel(), ids);
  22. #[cfg(feature = "mounted")]
  23. for id in to_mount {
  24. self.send_mount_event(id);
  25. }
  26. Ok(())
  27. }
  28. fn rehydrate_scope(
  29. &mut self,
  30. scope: &ScopeState,
  31. dom: &VirtualDom,
  32. ids: &mut Vec<u32>,
  33. to_mount: &mut Vec<ElementId>,
  34. ) -> Result<(), RehydrationError> {
  35. let vnode = scope.root_node();
  36. self.rehydrate_vnode(dom, vnode, ids, to_mount)
  37. }
  38. fn rehydrate_vnode(
  39. &mut self,
  40. dom: &VirtualDom,
  41. vnode: &VNode,
  42. ids: &mut Vec<u32>,
  43. to_mount: &mut Vec<ElementId>,
  44. ) -> Result<(), RehydrationError> {
  45. for (i, root) in vnode.template.get().roots.iter().enumerate() {
  46. self.rehydrate_template_node(
  47. dom,
  48. vnode,
  49. root,
  50. ids,
  51. to_mount,
  52. Some(vnode.mounted_root(i, dom).ok_or(VNodeNotInitialized)?),
  53. )?;
  54. }
  55. Ok(())
  56. }
  57. fn rehydrate_template_node(
  58. &mut self,
  59. dom: &VirtualDom,
  60. vnode: &VNode,
  61. node: &TemplateNode,
  62. ids: &mut Vec<u32>,
  63. to_mount: &mut Vec<ElementId>,
  64. root_id: Option<ElementId>,
  65. ) -> Result<(), RehydrationError> {
  66. tracing::trace!("rehydrate template node: {:?}", node);
  67. match node {
  68. TemplateNode::Element {
  69. children, attrs, ..
  70. } => {
  71. let mut mounted_id = root_id;
  72. for attr in *attrs {
  73. if let dioxus_core::TemplateAttribute::Dynamic { id } = attr {
  74. let attributes = &*vnode.dynamic_attrs[*id];
  75. let id = vnode
  76. .mounted_dynamic_attribute(*id, dom)
  77. .ok_or(VNodeNotInitialized)?;
  78. for attribute in attributes {
  79. let value = &attribute.value;
  80. mounted_id = Some(id);
  81. if let AttributeValue::Listener(_) = value {
  82. if attribute.name == "onmounted" {
  83. to_mount.push(id);
  84. }
  85. }
  86. }
  87. }
  88. }
  89. if let Some(id) = mounted_id {
  90. ids.push(id.0 as u32);
  91. }
  92. if !children.is_empty() {
  93. for child in *children {
  94. self.rehydrate_template_node(dom, vnode, child, ids, to_mount, None)?;
  95. }
  96. }
  97. }
  98. TemplateNode::Dynamic { id } | TemplateNode::DynamicText { id } => self
  99. .rehydrate_dynamic_node(
  100. dom,
  101. &vnode.dynamic_nodes[*id],
  102. *id,
  103. vnode,
  104. ids,
  105. to_mount,
  106. )?,
  107. _ => {}
  108. }
  109. Ok(())
  110. }
  111. fn rehydrate_dynamic_node(
  112. &mut self,
  113. dom: &VirtualDom,
  114. dynamic: &DynamicNode,
  115. dynamic_node_index: usize,
  116. vnode: &VNode,
  117. ids: &mut Vec<u32>,
  118. to_mount: &mut Vec<ElementId>,
  119. ) -> Result<(), RehydrationError> {
  120. tracing::trace!("rehydrate dynamic node: {:?}", dynamic);
  121. match dynamic {
  122. dioxus_core::DynamicNode::Text(_) | dioxus_core::DynamicNode::Placeholder(_) => {
  123. ids.push(
  124. vnode
  125. .mounted_dynamic_node(dynamic_node_index, dom)
  126. .ok_or(VNodeNotInitialized)?
  127. .0 as u32,
  128. );
  129. }
  130. dioxus_core::DynamicNode::Component(comp) => {
  131. let scope = comp
  132. .mounted_scope(dynamic_node_index, vnode, dom)
  133. .ok_or(VNodeNotInitialized)?;
  134. self.rehydrate_scope(scope, dom, ids, to_mount)?;
  135. }
  136. dioxus_core::DynamicNode::Fragment(fragment) => {
  137. for vnode in fragment {
  138. self.rehydrate_vnode(dom, vnode, ids, to_mount)?;
  139. }
  140. }
  141. }
  142. Ok(())
  143. }
  144. }
  145. /// During rehydration, we don't want to actually write anything to the DOM, but we do need to store any templates that were created. This struct is used to only write templates to the DOM.
  146. pub(crate) struct OnlyWriteTemplates<'a>(pub &'a mut WebsysDom);
  147. impl WriteMutations for OnlyWriteTemplates<'_> {
  148. fn register_template(&mut self, template: Template) {
  149. let mut roots = vec![];
  150. for root in template.roots {
  151. roots.push(self.0.create_template_node(root))
  152. }
  153. self.0
  154. .templates
  155. .insert(template.name.to_owned(), self.0.max_template_id);
  156. save_template(
  157. self.0.interpreter.js_channel(),
  158. roots,
  159. self.0.max_template_id,
  160. );
  161. self.0.max_template_id += 1
  162. }
  163. fn append_children(&mut self, _: ElementId, _: usize) {}
  164. fn assign_node_id(&mut self, _: &'static [u8], _: ElementId) {}
  165. fn create_placeholder(&mut self, _: ElementId) {}
  166. fn create_text_node(&mut self, _: &str, _: ElementId) {}
  167. fn hydrate_text_node(&mut self, _: &'static [u8], _: &str, _: ElementId) {}
  168. fn load_template(&mut self, _: &'static str, _: usize, _: ElementId) {}
  169. fn replace_node_with(&mut self, _: ElementId, _: usize) {}
  170. fn replace_placeholder_with_nodes(&mut self, _: &'static [u8], _: usize) {}
  171. fn insert_nodes_after(&mut self, _: ElementId, _: usize) {}
  172. fn insert_nodes_before(&mut self, _: ElementId, _: usize) {}
  173. fn set_attribute(
  174. &mut self,
  175. _: &'static str,
  176. _: Option<&'static str>,
  177. _: &AttributeValue,
  178. _: ElementId,
  179. ) {
  180. }
  181. fn set_node_text(&mut self, _: &str, _: ElementId) {}
  182. fn create_event_listener(&mut self, _: &'static str, _: ElementId) {}
  183. fn remove_event_listener(&mut self, _: &'static str, _: ElementId) {}
  184. fn remove_node(&mut self, _: ElementId) {}
  185. fn push_root(&mut self, _: ElementId) {}
  186. }