1
0

scopes.rs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. use crate::{
  2. any_props::BoxedAnyProps, nodes::AsVNode, reactive_context::ReactiveContext,
  3. scope_context::Scope, Element, Runtime, VNode,
  4. };
  5. use std::{cell::Ref, rc::Rc};
  6. /// A component's unique identifier.
  7. ///
  8. /// `ScopeId` is a `usize` that acts a key for the internal slab of Scopes. This means that the key is not unique across
  9. /// time. We do try and guarantee that between calls to `wait_for_work`, no ScopeIds will be recycled in order to give
  10. /// time for any logic that relies on these IDs to properly update.
  11. #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
  12. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
  13. pub struct ScopeId(pub usize);
  14. impl std::fmt::Debug for ScopeId {
  15. #[allow(unused_mut)]
  16. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  17. let mut builder = f.debug_tuple("ScopeId");
  18. let mut builder = builder.field(&self.0);
  19. #[cfg(debug_assertions)]
  20. {
  21. if let Some(name) = Runtime::current()
  22. .ok()
  23. .as_ref()
  24. .and_then(|rt| rt.get_state(*self))
  25. {
  26. builder = builder.field(&name.name);
  27. }
  28. }
  29. builder.finish()
  30. }
  31. }
  32. impl ScopeId {
  33. /// The ScopeId of the main scope passed into [`VirtualDom::new`].
  34. ///
  35. /// This scope will last for the entire duration of your app, making it convenient for long-lived state
  36. /// that is created dynamically somewhere down the component tree.
  37. ///
  38. /// # Example
  39. ///
  40. /// ```rust, no_run
  41. /// use dioxus::prelude::*;
  42. /// let my_persistent_state = Signal::new_in_scope(String::new(), ScopeId::APP);
  43. /// ```
  44. // ScopeId(0) is the root scope wrapper
  45. // ScopeId(1) is the default error boundary
  46. // ScopeId(2) is the default suspense boundary
  47. // ScopeId(3) is the users root scope
  48. pub const APP: ScopeId = ScopeId(3);
  49. /// The ScopeId of the topmost scope in the tree.
  50. /// This will be higher up in the tree than [`ScopeId::APP`] because dioxus inserts a default [`SuspenseBoundary`] and [`ErrorBoundary`] at the root of the tree.
  51. // ScopeId(0) is the root scope wrapper
  52. pub const ROOT: ScopeId = ScopeId(0);
  53. pub(crate) const PLACEHOLDER: ScopeId = ScopeId(usize::MAX);
  54. pub(crate) fn is_placeholder(&self) -> bool {
  55. *self == Self::PLACEHOLDER
  56. }
  57. }
  58. /// A component's rendered state.
  59. ///
  60. /// This state erases the type of the component's props. It is used to store the state of a component in the runtime.
  61. pub struct ScopeState {
  62. pub(crate) runtime: Rc<Runtime>,
  63. pub(crate) context_id: ScopeId,
  64. /// The last node that has been rendered for this component. This node may not ben mounted
  65. /// During suspense, this component can be rendered in the background multiple times
  66. pub(crate) last_rendered_node: Option<Element>,
  67. pub(crate) props: BoxedAnyProps,
  68. pub(crate) reactive_context: ReactiveContext,
  69. }
  70. impl Drop for ScopeState {
  71. fn drop(&mut self) {
  72. self.runtime.remove_scope(self.context_id);
  73. }
  74. }
  75. impl ScopeState {
  76. /// Get a handle to the currently active head node arena for this Scope
  77. ///
  78. /// This is useful for traversing the tree outside of the VirtualDom, such as in a custom renderer or in SSR.
  79. ///
  80. /// Panics if the tree has not been built yet.
  81. pub fn root_node(&self) -> &VNode {
  82. self.try_root_node()
  83. .expect("The tree has not been built yet. Make sure to call rebuild on the tree before accessing its nodes.")
  84. }
  85. /// Try to get a handle to the currently active head node arena for this Scope
  86. ///
  87. /// This is useful for traversing the tree outside of the VirtualDom, such as in a custom renderer or in SSR.
  88. ///
  89. /// Returns [`None`] if the tree has not been built yet.
  90. pub fn try_root_node(&self) -> Option<&VNode> {
  91. self.last_rendered_node.as_ref().map(AsVNode::as_vnode)
  92. }
  93. /// Returns the scope id of this [`ScopeState`].
  94. pub fn id(&self) -> ScopeId {
  95. self.context_id
  96. }
  97. pub(crate) fn state(&self) -> Ref<'_, Scope> {
  98. self.runtime.get_state(self.context_id).unwrap()
  99. }
  100. }