dioxus-core 0.5.6

Core functionality for Dioxus - a concurrent renderer-agnostic Virtual DOM for interactive user experiences
Documentation
use crate::innerlude::ScopeOrder;
use crate::{
    any_props::{AnyProps, BoxedAnyProps},
    innerlude::ScopeState,
    nodes::RenderReturn,
    scope_context::Scope,
    scopes::ScopeId,
    virtual_dom::VirtualDom,
};

impl VirtualDom {
    pub(super) fn new_scope(&mut self, props: BoxedAnyProps, name: &'static str) -> &ScopeState {
        let parent_id = self.runtime.current_scope_id();
        let height = parent_id
            .and_then(|parent_id| self.runtime.get_state(parent_id).map(|f| f.height + 1))
            .unwrap_or(0);
        let entry = self.scopes.vacant_entry();
        let id = ScopeId(entry.key());

        let scope = entry.insert(ScopeState {
            runtime: self.runtime.clone(),
            context_id: id,
            props,
            last_rendered_node: Default::default(),
        });

        self.runtime
            .create_scope(Scope::new(name, id, parent_id, height));

        scope
    }

    pub(crate) fn run_scope(&mut self, scope_id: ScopeId) -> RenderReturn {
        debug_assert!(
            crate::Runtime::current().is_some(),
            "Must be in a dioxus runtime"
        );

        self.runtime.scope_stack.borrow_mut().push(scope_id);
        let scope = &self.scopes[scope_id.0];
        let new_nodes = {
            let context = scope.state();

            context.hook_index.set(0);

            // Run all pre-render hooks
            for pre_run in context.before_render.borrow_mut().iter_mut() {
                pre_run();
            }

            // safety: due to how we traverse the tree, we know that the scope is not currently aliased
            let props: &dyn AnyProps = &*scope.props;

            let span = tracing::trace_span!("render", scope = %scope.state().name);
            span.in_scope(|| props.render())
        };

        let context = scope.state();

        // Run all post-render hooks
        for post_run in context.after_render.borrow_mut().iter_mut() {
            post_run();
        }

        // And move the render generation forward by one
        context.render_count.set(context.render_count.get() + 1);

        // remove this scope from dirty scopes
        self.dirty_scopes
            .remove(&ScopeOrder::new(context.height, scope_id));

        if let Some(task) = context.last_suspendable_task.take() {
            if matches!(new_nodes, RenderReturn::Aborted(_)) {
                tracing::trace!("Suspending {:?} on {:?}", scope_id, task);
                self.runtime.tasks.borrow().get(task.0).unwrap().suspend();
                self.runtime
                    .suspended_tasks
                    .set(self.runtime.suspended_tasks.get() + 1);
            }
        }

        self.runtime.scope_stack.borrow_mut().pop();

        new_nodes
    }
}