Overview
Scopes represent individual component instances in the virtual DOM tree. Each component has its own scope that provides context, state management, and lifecycle control.
ScopeId
A unique identifier for a component scope.
pub struct ScopeId(pub usize);
Constants
The ID of the user’s root scope. This scope lasts for the entire app lifetime, making it convenient for long-lived state.// Create a signal in the app scope
let global_state = Signal::new_in_scope(
String::new(),
ScopeId::APP
);
The ID of the topmost scope in the tree. This is higher than APP because Dioxus inserts default error and suspense boundaries.
ScopeId::ROOT_ERROR_BOUNDARY
The ID of the topmost error boundary in the tree.
ScopeId::ROOT_SUSPENSE_BOUNDARY
The ID of the topmost suspense boundary in the tree.
Example Usage
use dioxus::prelude::*;
#[component]
fn MyComponent() -> Element {
// Get the current scope ID
let scope_id = current_scope_id().unwrap();
// Create state in a specific scope
let app_state = Signal::new_in_scope(0, ScopeId::APP);
rsx! {
div { "Scope ID: {scope_id:?}" }
}
}
ScopeState
Represents a component’s rendered state and provides access to the component’s runtime context.
pub struct ScopeState {
runtime: Rc<Runtime>,
context_id: ScopeId,
last_rendered_node: Option<LastRenderedNode>,
props: BoxedAnyProps,
reactive_context: ReactiveContext,
}
Methods
root_node()
Gets the currently active root node for this scope.
pub fn root_node(&self) -> &VNode
Panics if the tree hasn’t been built yet.
let scope = dom.get_scope(scope_id).unwrap();
let node = scope.root_node();
try_root_node()
Tries to get the root node, returning None if not built yet.
pub fn try_root_node(&self) -> Option<&VNode>
if let Some(node) = scope.try_root_node() {
// Process node
}
id()
Returns the scope’s ID.
pub fn id(&self) -> ScopeId
let scope = dom.get_scope(scope_id).unwrap();
let id = scope.id();
height()
Returns the scope’s height in the component tree.
pub fn height(&self) -> u32
The root scope has height 0, its children have height 1, etc.
let height = scope.height();
println!("Scope depth: {}", height);
Context API
Scopes provide context for sharing state down the component tree without prop drilling.
Providing Context
use dioxus::prelude::*;
#[derive(Clone)]
struct Theme {
primary_color: String,
font_size: u32,
}
#[component]
fn App() -> Element {
// Provide context for child components
provide_context(Theme {
primary_color: "#007bff".to_string(),
font_size: 16,
});
rsx! {
ThemedButton { text: "Click me" }
}
}
Consuming Context
#[component]
fn ThemedButton(text: String) -> Element {
// Consume context from parent
let theme = consume_context::<Theme>();
rsx! {
button {
style: "color: {theme.primary_color}; font-size: {theme.font_size}px",
"{text}"
}
}
}
Context Functions
Provides a context value to child components.pub fn provide_context<T: Clone + 'static>(value: T)
Consumes a context value from parent components. Panics if not found.pub fn consume_context<T: Clone + 'static>() -> T
Tries to consume a context value, returning None if not found.pub fn try_consume_context<T: Clone + 'static>() -> Option<T>
Checks if a context value exists in parent scopes.pub fn has_context<T: 'static>() -> bool
Scope Utilities
Getting Current Scope
use dioxus::prelude::*;
#[component]
fn MyComponent() -> Element {
let scope_id = current_scope_id().unwrap();
rsx! {
div { "Current scope: {scope_id:?}" }
}
}
Parent Scope
use dioxus::prelude::*;
#[component]
fn ChildComponent() -> Element {
let parent = parent_scope();
rsx! {
div { "Parent scope: {parent:?}" }
}
}
Owner Context
use dioxus::prelude::*;
#[component]
fn MyComponent() -> Element {
let owner = current_owner();
// Run code in a specific owner context
with_owner(owner, || {
// This code runs with the owner context
});
rsx! { div { "Hello" } }
}
Scheduling Updates
Manual Re-renders
use dioxus::prelude::*;
#[component]
fn MyComponent() -> Element {
// Schedule this component to re-render
schedule_update();
rsx! { div { "Will re-render" } }
}
Schedule Any Scope
// Schedule a specific scope to re-render
schedule_update_any(scope_id);
Lifecycle Hooks
Before Render
use dioxus::prelude::*;
#[component]
fn MyComponent() -> Element {
use_before_render(move || {
println!("About to render");
});
rsx! { div { "Hello" } }
}
After Render
#[component]
fn MyComponent() -> Element {
use_after_render(move || {
println!("Finished rendering");
});
rsx! { div { "Hello" } }
}
On Drop
#[component]
fn MyComponent() -> Element {
use_drop(move || {
println!("Component unmounting");
});
rsx! { div { "Hello" } }
}
Reactive Context
The reactive context tracks signal subscriptions for automatic re-renders.
#[component]
fn Counter() -> Element {
let mut count = use_signal(|| 0);
// Reading count subscribes this scope to updates
let current = count();
rsx! {
div {
p { "Count: {current}" }
button {
// Writing to count triggers re-render
onclick: move |_| count += 1,
"Increment"
}
}
}
}
Scope Hierarchy
// Root Scope (ScopeId::ROOT)
// ├─ Suspense Boundary (ScopeId::ROOT_SUSPENSE_BOUNDARY)
// │ └─ Error Boundary (ScopeId::ROOT_ERROR_BOUNDARY)
// │ └─ App Component (ScopeId::APP)
// │ ├─ Child Component (ScopeId(4))
// │ └─ Child Component (ScopeId(5))
Traversing the Tree
use dioxus::prelude::*;
fn print_scope_tree(dom: &VirtualDom, scope_id: ScopeId, depth: usize) {
let scope = dom.get_scope(scope_id).unwrap();
let indent = " ".repeat(depth);
println!("{}{:?} (height: {})", indent, scope_id, scope.height());
}
Advanced Usage
Custom Scope Storage
use dioxus::prelude::*;
#[derive(Clone)]
struct ScopeData {
created_at: std::time::Instant,
}
#[component]
fn MyComponent() -> Element {
// Store custom data in scope context
provide_context(ScopeData {
created_at: std::time::Instant::now(),
});
rsx! { div { "Component initialized" } }
}
Accessing VirtualDom from Scope
// In custom renderers or advanced use cases
let scope = dom.get_scope(scope_id).unwrap();
let root_node = scope.root_node();
// Traverse the rendered tree
for root in &root_node.template.roots {
// Process template nodes
}
See Also