1
0

component.rs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. use std::{
  2. cell::RefMut,
  3. ops::{Deref, DerefMut},
  4. };
  5. use crate::{
  6. any_props::AnyProps,
  7. arena::ElementId,
  8. innerlude::{
  9. DirtyScope, ElementPath, ElementRef, VComponent, VNodeMount, VText, WriteMutations,
  10. },
  11. nodes::RenderReturn,
  12. nodes::{DynamicNode, VNode},
  13. scopes::ScopeId,
  14. virtual_dom::VirtualDom,
  15. TemplateNode,
  16. };
  17. use DynamicNode::*;
  18. impl VirtualDom {
  19. pub(crate) fn diff_scope(
  20. &mut self,
  21. to: &mut impl WriteMutations,
  22. scope: ScopeId,
  23. new_nodes: RenderReturn,
  24. ) {
  25. self.runtime.scope_stack.borrow_mut().push(scope);
  26. let scope_state = &mut self.scopes[scope.0];
  27. // Load the old and new bump arenas
  28. let new = &new_nodes;
  29. let old = scope_state.last_rendered_node.take().unwrap();
  30. use RenderReturn::{Aborted, Ready};
  31. let (Ready(old) | Aborted(old), Ready(new) | Aborted(new)) = (&old, new);
  32. old.diff_node(new, self, to);
  33. let scope_state = &mut self.scopes[scope.0];
  34. scope_state.last_rendered_node = Some(new_nodes);
  35. self.runtime.scope_stack.borrow_mut().pop();
  36. }
  37. /// Create a new template [`VNode`] and write it to the [`Mutations`] buffer.
  38. ///
  39. /// This method pushes the ScopeID to the internal scopestack and returns the number of nodes created.
  40. pub(crate) fn create_scope(
  41. &mut self,
  42. to: &mut impl WriteMutations,
  43. scope: ScopeId,
  44. new_node: &VNode,
  45. parent: Option<ElementRef>,
  46. ) -> usize {
  47. self.runtime.scope_stack.borrow_mut().push(scope);
  48. let nodes = new_node.create(self, to, parent);
  49. self.runtime.scope_stack.borrow_mut().pop();
  50. nodes
  51. }
  52. }
  53. impl VNode {
  54. pub(crate) fn diff_vcomponent(
  55. &self,
  56. mount: &mut VNodeMount,
  57. idx: usize,
  58. new: &VComponent,
  59. old: &VComponent,
  60. scope_id: ScopeId,
  61. parent: Option<ElementRef>,
  62. dom: &mut VirtualDom,
  63. to: &mut impl WriteMutations,
  64. ) {
  65. // Replace components that have different render fns
  66. if old.render_fn != new.render_fn {
  67. return self.replace_vcomponent(mount, idx, new, parent, dom, to);
  68. }
  69. // copy out the box for both
  70. let old_scope = &mut dom.scopes[scope_id.0];
  71. let old_props = old_scope.props.deref();
  72. let new_props: &dyn AnyProps = new.props.deref();
  73. // If the props are static, then we try to memoize by setting the new with the old
  74. // The target scopestate still has the reference to the old props, so there's no need to update anything
  75. // This also implicitly drops the new props since they're not used
  76. if old_props.memoize(new_props.props()) {
  77. tracing::trace!(
  78. "Memoized props for component {:#?} ({})",
  79. scope_id,
  80. old_scope.context().name
  81. );
  82. return;
  83. }
  84. // First, move over the props from the old to the new, dropping old props in the process
  85. dom.scopes[scope_id.0].props = new.props.clone();
  86. // Now run the component and diff it
  87. let new = dom.run_scope(scope_id);
  88. dom.diff_scope(to, scope_id, new);
  89. let height = dom.runtime.get_context(scope_id).unwrap().height;
  90. dom.dirty_scopes.remove(&DirtyScope {
  91. height,
  92. id: scope_id,
  93. });
  94. }
  95. fn replace_vcomponent(
  96. &self,
  97. mount: &mut VNodeMount,
  98. idx: usize,
  99. new: &VComponent,
  100. parent: Option<ElementRef>,
  101. dom: &mut VirtualDom,
  102. to: &mut impl WriteMutations,
  103. ) {
  104. let scope = ScopeId(mount.mounted_dynamic_nodes[idx]);
  105. let _m = self.create_component_node(mount, idx, new, parent, dom, to);
  106. // TODO: Instead of *just* removing it, we can use the replace mutation
  107. dom.remove_component_node(to, scope, true);
  108. todo!()
  109. }
  110. pub(super) fn create_component_node(
  111. &self,
  112. mount: &mut VNodeMount,
  113. idx: usize,
  114. component: &VComponent,
  115. parent: Option<ElementRef>,
  116. dom: &mut VirtualDom,
  117. to: &mut impl WriteMutations,
  118. ) -> usize {
  119. // Load up a ScopeId for this vcomponent. If it's already mounted, then we can just use that
  120. let scope = dom
  121. .new_scope(component.props.clone(), component.name)
  122. .context()
  123. .id;
  124. let mut new = dom.run_scope(scope);
  125. dom.scopes[scope.0].last_rendered_node = Some(new.clone());
  126. dom.create_scope(to, scope, &new, parent)
  127. }
  128. }