mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-23 04:33:06 +00:00
fix scope context
This commit is contained in:
parent
04cdb14e5b
commit
cb4c46154d
7 changed files with 83 additions and 45 deletions
|
@ -3,15 +3,13 @@
|
||||||
//! The example from the README.md.
|
//! The example from the README.md.
|
||||||
|
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use dioxus_signals::{use_init_signal_rt, use_signal};
|
use dioxus_signals::use_signal;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
dioxus_desktop::launch(app);
|
dioxus_desktop::launch(app);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn app(cx: Scope) -> Element {
|
fn app(cx: Scope) -> Element {
|
||||||
use_init_signal_rt(cx);
|
|
||||||
|
|
||||||
let mut count = use_signal(cx, || 0);
|
let mut count = use_signal(cx, || 0);
|
||||||
|
|
||||||
use_future!(cx, || async move {
|
use_future!(cx, || async move {
|
||||||
|
|
|
@ -110,11 +110,13 @@ impl VirtualDom {
|
||||||
// Drop all the hooks once the children are dropped
|
// Drop all the hooks once the children are dropped
|
||||||
// this means we'll drop hooks bottom-up
|
// this means we'll drop hooks bottom-up
|
||||||
scope.hooks.get_mut().clear();
|
scope.hooks.get_mut().clear();
|
||||||
let context = scope.context();
|
{
|
||||||
|
let context = scope.context();
|
||||||
|
|
||||||
// Drop all the futures once the hooks are dropped
|
// Drop all the futures once the hooks are dropped
|
||||||
for task_id in context.spawned_tasks.borrow_mut().drain() {
|
for task_id in context.spawned_tasks.borrow_mut().drain() {
|
||||||
context.tasks.remove(task_id);
|
context.tasks.remove(task_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.scopes.remove(id.0);
|
self.scopes.remove(id.0);
|
||||||
|
|
|
@ -209,7 +209,7 @@ impl<'b> VirtualDom {
|
||||||
self.diff_scope(scope_id);
|
self.diff_scope(scope_id);
|
||||||
|
|
||||||
self.dirty_scopes.remove(&DirtyScope {
|
self.dirty_scopes.remove(&DirtyScope {
|
||||||
height: self.runtime.scope_contexts[scope_id.0].height,
|
height: self.runtime.get_context(scope_id).unwrap().height,
|
||||||
id: scope_id,
|
id: scope_id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,14 @@
|
||||||
use std::cell::RefCell;
|
use std::cell::{Ref, RefCell};
|
||||||
|
|
||||||
use crate::{
|
use crate::{innerlude::Scheduler, scope_context::ScopeContext, scopes::ScopeId};
|
||||||
innerlude::{DirtyScope, Scheduler, SchedulerMsg},
|
use std::rc::Rc;
|
||||||
scope_context::ScopeContext,
|
|
||||||
scopes::{ScopeId, ScopeState},
|
|
||||||
};
|
|
||||||
use rustc_hash::FxHashSet;
|
|
||||||
use slab::Slab;
|
|
||||||
use std::{collections::BTreeSet, rc::Rc};
|
|
||||||
|
|
||||||
thread_local! {
|
thread_local! {
|
||||||
static RUNTIMES: RefCell<Vec<Runtime>> = RefCell::new(vec![]);
|
static RUNTIMES: RefCell<Vec<Rc<Runtime>>> = RefCell::new(vec![]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pushes a new scope onto the stack
|
/// Pushes a new scope onto the stack
|
||||||
pub(crate) fn push_runtime(runtime: Runtime) {
|
pub(crate) fn push_runtime(runtime: Rc<Runtime>) {
|
||||||
RUNTIMES.with(|stack| stack.borrow_mut().push(runtime));
|
RUNTIMES.with(|stack| stack.borrow_mut().push(runtime));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +24,7 @@ where
|
||||||
{
|
{
|
||||||
RUNTIMES.with(|stack| {
|
RUNTIMES.with(|stack| {
|
||||||
let stack = stack.borrow();
|
let stack = stack.borrow();
|
||||||
stack.last().map(f)
|
stack.last().map(|r| f(&**r))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,28 +36,50 @@ where
|
||||||
with_runtime(|runtime| {
|
with_runtime(|runtime| {
|
||||||
runtime
|
runtime
|
||||||
.current_scope_id()
|
.current_scope_id()
|
||||||
.and_then(|scope| runtime.get_context(scope).map(f))
|
.and_then(|scope| runtime.get_context(scope).map(|sc| f(&*sc)))
|
||||||
})
|
})
|
||||||
.flatten()
|
.flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Runtime {
|
pub struct Runtime {
|
||||||
pub(crate) scope_contexts: Slab<ScopeContext>,
|
pub(crate) scope_contexts: RefCell<Vec<Option<ScopeContext>>>,
|
||||||
pub(crate) scheduler: Rc<Scheduler>,
|
pub(crate) scheduler: Rc<Scheduler>,
|
||||||
|
|
||||||
// While diffing we need some sort of way of breaking off a stream of suspended mutations.
|
// While diffing we need some sort of way of breaking off a stream of suspended mutations.
|
||||||
pub(crate) scope_stack: RefCell<Vec<ScopeId>>,
|
pub(crate) scope_stack: RefCell<Vec<ScopeId>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Drop for Runtime {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
// todo: do this better
|
||||||
|
pop_runtime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Runtime {
|
impl Runtime {
|
||||||
pub(crate) fn new(scheduler: Rc<Scheduler>) -> Rc<Self> {
|
pub(crate) fn new(scheduler: Rc<Scheduler>) -> Rc<Self> {
|
||||||
Rc::new(Self {
|
let runtime = Rc::new(Self {
|
||||||
scheduler,
|
scheduler,
|
||||||
|
|
||||||
scope_contexts: Default::default(),
|
scope_contexts: Default::default(),
|
||||||
|
|
||||||
scope_stack: Default::default(),
|
scope_stack: Default::default(),
|
||||||
})
|
});
|
||||||
|
push_runtime(runtime.clone());
|
||||||
|
runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a scope context. This slab is synchronized with the scope slab.
|
||||||
|
pub(crate) fn create_context_at(&self, id: ScopeId, context: ScopeContext) {
|
||||||
|
let mut contexts = self.scope_contexts.borrow_mut();
|
||||||
|
if contexts.len() <= id.0 {
|
||||||
|
contexts.resize_with(id.0 + 1, Default::default);
|
||||||
|
}
|
||||||
|
contexts[id.0] = Some(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn remove_context(&self, id: ScopeId) {
|
||||||
|
self.scope_contexts.borrow_mut()[id.0] = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the current scope id
|
/// Get the current scope id
|
||||||
|
@ -71,17 +87,13 @@ impl Runtime {
|
||||||
self.scope_stack.borrow().last().copied()
|
self.scope_stack.borrow().last().copied()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the state for any scope given its ID
|
/// Get the context for any scope given its ID
|
||||||
///
|
///
|
||||||
/// This is useful for inserting or removing contexts from a scope, or rendering out its root node
|
/// This is useful for inserting or removing contexts from a scope, or rendering out its root node
|
||||||
pub fn get_context(&self, id: ScopeId) -> Option<&ScopeContext> {
|
pub fn get_context(&self, id: ScopeId) -> Option<Ref<'_, ScopeContext>> {
|
||||||
self.scope_contexts.get(id.0).map(|f| &*f)
|
Ref::filter_map(self.scope_contexts.borrow(), |contexts| {
|
||||||
}
|
contexts.get(id.0).and_then(|f| f.as_ref())
|
||||||
|
})
|
||||||
/// Get the single scope at the top of the Runtime tree that will always be around
|
.ok()
|
||||||
///
|
|
||||||
/// This scope has a ScopeId of 0 and is the root of the tree
|
|
||||||
pub fn base_context(&self) -> &ScopeContext {
|
|
||||||
self.get_context(ScopeId(0)).unwrap()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ use crate::{
|
||||||
bump_frame::BumpFrame,
|
bump_frame::BumpFrame,
|
||||||
innerlude::DirtyScope,
|
innerlude::DirtyScope,
|
||||||
nodes::RenderReturn,
|
nodes::RenderReturn,
|
||||||
|
scope_context::ScopeContext,
|
||||||
scopes::{ScopeId, ScopeState},
|
scopes::{ScopeId, ScopeState},
|
||||||
virtual_dom::VirtualDom,
|
virtual_dom::VirtualDom,
|
||||||
};
|
};
|
||||||
|
@ -20,7 +21,7 @@ impl VirtualDom {
|
||||||
let entry = self.scopes.vacant_entry();
|
let entry = self.scopes.vacant_entry();
|
||||||
let id = ScopeId(entry.key());
|
let id = ScopeId(entry.key());
|
||||||
|
|
||||||
entry.insert(ScopeState {
|
let scope = entry.insert(ScopeState {
|
||||||
runtime: self.runtime.clone(),
|
runtime: self.runtime.clone(),
|
||||||
context_id: id,
|
context_id: id,
|
||||||
|
|
||||||
|
@ -35,7 +36,13 @@ impl VirtualDom {
|
||||||
|
|
||||||
borrowed_props: Default::default(),
|
borrowed_props: Default::default(),
|
||||||
attributes_to_drop: Default::default(),
|
attributes_to_drop: Default::default(),
|
||||||
})
|
});
|
||||||
|
|
||||||
|
let context =
|
||||||
|
ScopeContext::new(name, id, parent_id, height, self.runtime.scheduler.clone());
|
||||||
|
self.runtime.create_context_at(id, context);
|
||||||
|
|
||||||
|
scope
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn run_scope(&mut self, scope_id: ScopeId) -> &RenderReturn {
|
pub(crate) fn run_scope(&mut self, scope_id: ScopeId) -> &RenderReturn {
|
||||||
|
|
|
@ -32,12 +32,23 @@ pub struct ScopeContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScopeContext {
|
impl ScopeContext {
|
||||||
pub fn name(&self) -> &str {
|
pub(crate) fn new(
|
||||||
self.name
|
name: &'static str,
|
||||||
}
|
id: ScopeId,
|
||||||
|
parent_id: Option<ScopeId>,
|
||||||
pub fn height(&self) -> u32 {
|
height: u32,
|
||||||
self.height
|
tasks: Rc<Scheduler>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
id,
|
||||||
|
parent_id,
|
||||||
|
height,
|
||||||
|
suspended: Cell::new(false),
|
||||||
|
shared_contexts: RefCell::new(vec![]),
|
||||||
|
tasks,
|
||||||
|
spawned_tasks: RefCell::new(FxHashSet::default()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parent_id(&self) -> Option<ScopeId> {
|
pub fn parent_id(&self) -> Option<ScopeId> {
|
||||||
|
|
|
@ -13,7 +13,7 @@ use crate::{
|
||||||
use bumpalo::{boxed::Box as BumpBox, Bump};
|
use bumpalo::{boxed::Box as BumpBox, Bump};
|
||||||
use std::{
|
use std::{
|
||||||
any::Any,
|
any::Any,
|
||||||
cell::{Cell, RefCell, UnsafeCell},
|
cell::{Cell, Ref, RefCell, UnsafeCell},
|
||||||
fmt::{Arguments, Debug},
|
fmt::{Arguments, Debug},
|
||||||
future::Future,
|
future::Future,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
|
@ -84,8 +84,14 @@ pub struct ScopeState {
|
||||||
pub(crate) props: Option<Box<dyn AnyProps<'static>>>,
|
pub(crate) props: Option<Box<dyn AnyProps<'static>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Drop for ScopeState {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.runtime.remove_context(self.context_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'src> ScopeState {
|
impl<'src> ScopeState {
|
||||||
pub(crate) fn context(&self) -> &ScopeContext {
|
pub(crate) fn context(&self) -> Ref<'_, ScopeContext> {
|
||||||
self.runtime.get_context(self.context_id).unwrap()
|
self.runtime.get_context(self.context_id).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -494,7 +500,9 @@ impl<'src> ScopeState {
|
||||||
|
|
||||||
/// Mark this component as suspended and then return None
|
/// Mark this component as suspended and then return None
|
||||||
pub fn suspend(&self) -> Option<Element> {
|
pub fn suspend(&self) -> Option<Element> {
|
||||||
self.context().suspend()
|
let cx = self.context();
|
||||||
|
cx.suspend();
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Store a value between renders. The foundational hook for all other hooks.
|
/// Store a value between renders. The foundational hook for all other hooks.
|
||||||
|
|
Loading…
Reference in a new issue