make desktop compile

This commit is contained in:
Evan Almloff committed 2024-01-05 14:39:45 -06:00
1 parent 21b71e992f
commit 3865f44081
27 files changed
+357 -422

No files matched your search

+5 -11
View File
@@ -1,5 +1,5 @@
use crate::{
scope_context::{consume_context, current_scope_id, schedule_update_any},
global_context::{consume_context, current_scope_id},
Element, IntoDynNode, Properties, ScopeId, Template, TemplateAttribute, TemplateNode, VNode,
};
use std::{
@@ -9,7 +9,6 @@ use std::{
error::Error,
fmt::{Debug, Display},
rc::Rc,
sync::Arc,
};
/// Provide an error boundary to catch errors from child components
@@ -28,7 +27,6 @@ pub struct ErrorBoundary {
pub struct ErrorBoundaryInner {
error: RefCell<Option<CapturedError>>,
_id: ScopeId,
rerun_boundary: Arc<dyn Fn(ScopeId) + Send + Sync>,
}
impl Debug for ErrorBoundaryInner {
@@ -81,7 +79,6 @@ impl Default for ErrorBoundaryInner {
error: RefCell::new(None),
_id: current_scope_id()
.expect("Cannot create an error boundary outside of a component's scope."),
rerun_boundary: schedule_update_any().unwrap(),
}
}
}
@@ -93,15 +90,11 @@ impl ErrorBoundary {
}
/// Create a new error boundary in the current scope
pub(crate) fn new_in_scope(
scope: ScopeId,
rerun_boundary: Arc<dyn Fn(ScopeId) + Send + Sync>,
) -> Self {
pub(crate) fn new_in_scope(scope: ScopeId) -> Self {
Self {
inner: Rc::new(ErrorBoundaryInner {
error: RefCell::new(None),
_id: scope,
rerun_boundary,
}),
}
}
@@ -113,13 +106,14 @@ impl ErrorBoundary {
error: Box<dyn Debug + 'static>,
backtrace: Backtrace,
) {
println!("{:?} {:?}", error, self.inner._id);
self.inner.error.replace(Some(CapturedError {
error,
scope,
backtrace,
}));
(self.inner.rerun_boundary)(self.inner._id);
if self.inner._id != ScopeId::ROOT {
self.inner._id.needs_update();
}
}
/// Take any error that has been captured by this error boundary
+1 -1
View File
@@ -1,4 +1,4 @@
use crate::{runtime::with_runtime, scope_context::current_scope_id, ScopeId};
use crate::{global_context::current_scope_id, runtime::with_runtime, ScopeId};
use std::{
cell::{Cell, RefCell},
rc::Rc,
+115
View File
@@ -0,0 +1,115 @@
use futures_util::Future;
use crate::{
runtime::{with_current_scope, with_runtime},
Element, ScopeId, Task,
};
/// Get the current scope id
pub fn current_scope_id() -> Option<ScopeId> {
with_runtime(|rt| rt.current_scope_id()).flatten()
}
#[doc(hidden)]
/// Check if the virtual dom is currently inside of the body of a component
pub fn vdom_is_rendering() -> bool {
with_runtime(|rt| rt.rendering.get()).unwrap_or_default()
}
/// Consume context from the current scope
pub fn consume_context<T: 'static + Clone>() -> Option<T> {
with_current_scope(|cx| cx.consume_context::<T>()).flatten()
}
/// Consume context from the current scope
pub fn consume_context_from_scope<T: 'static + Clone>(scope_id: ScopeId) -> Option<T> {
with_runtime(|rt| {
rt.get_context(scope_id)
.and_then(|cx| cx.consume_context::<T>())
})
.flatten()
}
/// Check if the current scope has a context
pub fn has_context<T: 'static + Clone>() -> Option<T> {
with_current_scope(|cx| cx.has_context::<T>()).flatten()
}
/// Provide context to the current scope
pub fn provide_context<T: 'static + Clone>(value: T) -> Option<T> {
with_current_scope(|cx| cx.provide_context(value))
}
/// Provide a context to the root scope
pub fn provide_root_context<T: 'static + Clone>(value: T) -> Option<T> {
with_current_scope(|cx| cx.provide_root_context(value))
}
/// Suspends the current component
pub fn suspend() -> Option<Element> {
with_current_scope(|cx| {
cx.suspend();
});
None
}
/// Pushes the future onto the poll queue to be polled after the component renders.
pub fn push_future(fut: impl Future<Output = ()> + 'static) -> Option<Task> {
with_current_scope(|cx| cx.push_future(fut))
}
/// Spawns the future but does not return the [`TaskId`]
pub fn spawn(fut: impl Future<Output = ()> + 'static) {
with_current_scope(|cx| cx.spawn(fut));
}
/// Spawn a future that Dioxus won't clean up when this component is unmounted
///
/// This is good for tasks that need to be run after the component has been dropped.
pub fn spawn_forever(fut: impl Future<Output = ()> + 'static) -> Option<Task> {
with_current_scope(|cx| cx.spawn_forever(fut))
}
/// Informs the scheduler that this task is no longer needed and should be removed.
///
/// This drops the task immediately.
pub fn remove_future(id: Task) {
with_current_scope(|cx| cx.remove_future(id));
}
/// Store a value between renders. The foundational hook for all other hooks.
///
/// Accepts an `initializer` closure, which is run on the first use of the hook (typically the initial render). The return value of this closure is stored for the lifetime of the component, and a mutable reference to it is provided on every render as the return value of `use_hook`.
///
/// When the component is unmounted (removed from the UI), the value is dropped. This means you can return a custom type and provide cleanup code by implementing the [`Drop`] trait
///
/// # Example
///
/// ```
/// use dioxus_core::ScopeState;
///
/// // prints a greeting on the initial render
/// pub fn use_hello_world() {
/// once(|| println!("Hello, world!"));
/// }
/// ```
pub fn once<State: Clone + 'static>(initializer: impl FnOnce() -> State) -> State {
with_current_scope(|cx| cx.use_hook(initializer)).expect("to be in a dioxus runtime")
}
/// Get the current render since the inception of this component
///
/// This can be used as a helpful diagnostic when debugging hooks/renders, etc
pub fn generation() -> Option<usize> {
with_current_scope(|cx| Some(cx.generation())).expect("to be in a dioxus runtime")
}
/// Get the parent of the current scope if it exists
pub fn parent_scope() -> Option<ScopeId> {
with_current_scope(|cx| cx.parent_id()).flatten()
}
/// Mark the current scope as dirty, causing it to re-render
pub fn needs_update() {
with_current_scope(|cx| cx.needs_update());
}
+9 -8
View File
@@ -11,6 +11,7 @@ mod dirty_scope;
mod error_boundary;
mod events;
mod fragment;
mod global_context;
mod mutations;
mod nodes;
mod properties;
@@ -27,13 +28,13 @@ pub(crate) mod innerlude {
pub use crate::error_boundary::*;
pub use crate::events::*;
pub use crate::fragment::*;
pub use crate::global_context::*;
pub use crate::mutations::*;
pub use crate::nodes::RenderReturn;
pub use crate::nodes::*;
pub use crate::properties::*;
pub use crate::runtime::{Runtime, RuntimeGuard};
pub use crate::scheduler::*;
pub use crate::scope_context::*;
pub use crate::scopes::*;
pub use crate::virtual_dom::*;
@@ -75,8 +76,8 @@ pub(crate) mod innerlude {
pub use crate::innerlude::{
fc_to_builder, generation, once, vdom_is_rendering, AnyValue, Attribute, AttributeValue,
CapturedError, Component, DynamicNode, Element, ElementId, Event, Fragment, IntoDynNode,
Mutation, MutationsVec, Properties, RenderReturn, ScopeId, ScopeState, TaskId, Template,
TemplateAttribute, TemplateNode, VComponent, VNode, VPlaceholder, VText, VirtualDom,
Mutation, MutationsVec, Properties, RenderReturn, ScopeId, Task, Template, TemplateAttribute,
TemplateNode, VComponent, VNode, VPlaceholder, VText, VirtualDom, WriteMutations,
};
/// The purpose of this module is to alleviate imports of many common types
@@ -85,10 +86,10 @@ pub use crate::innerlude::{
pub mod prelude {
pub use crate::innerlude::{
consume_context, consume_context_from_scope, current_scope_id, fc_to_builder, generation,
has_context, once, provide_context, provide_context_to_scope, provide_root_context,
push_future, remove_future, schedule_update_any, spawn, spawn_forever, suspend,
use_error_boundary, AnyValue, Component, Element, ErrorBoundary, Event, EventHandler,
Fragment, IntoAttributeValue, IntoDynNode, Properties, Runtime, RuntimeGuard, ScopeId,
TaskId, Template, TemplateAttribute, TemplateNode, Throw, VNode, VirtualDom,
has_context, needs_update, once, parent_scope, provide_context, provide_root_context,
push_future, remove_future, spawn, spawn_forever, suspend, use_error_boundary, AnyValue,
Component, Element, ErrorBoundary, Event, EventHandler, Fragment, IntoAttributeValue,
IntoDynNode, Properties, Runtime, RuntimeGuard, ScopeId, Task, Template, TemplateAttribute,
TemplateNode, Throw, VNode, VirtualDom,
};
}
+1 -2
View File
@@ -518,8 +518,7 @@ impl Attribute {
///
/// "Volatile" referes to whether or not Dioxus should always override the value. This helps prevent the UI in
/// some renderers stay in sync with the VirtualDom's understanding of the world
pub fn attr(
&self,
pub fn new(
name: &'static str,
value: impl IntoAttributeValue,
namespace: Option<&'static str>,
+9 -1
View File
@@ -41,6 +41,14 @@ where
.flatten()
}
/// Runs a function with the current scope
pub(crate) fn with_scope<F, R>(scope: ScopeId, f: F) -> Option<R>
where
F: FnOnce(&ScopeContext) -> R,
{
with_runtime(|runtime| runtime.get_context(scope).map(|sc| f(&sc))).flatten()
}
/// A global runtime that is shared across all scopes that provides the async runtime and context API
pub struct Runtime {
pub(crate) scope_contexts: RefCell<Vec<Option<ScopeContext>>>,
@@ -98,7 +106,7 @@ impl Runtime {
}
}
/// A gaurd for a new runtime. This must be used to override the current runtime when importing components from a dynamic library that has it's own runtime.
/// A guard for a new runtime. This must be used to override the current runtime when importing components from a dynamic library that has it's own runtime.
///
/// ```rust
/// use dioxus::prelude::*;
+1 -1
View File
@@ -15,7 +15,7 @@ pub(crate) enum SchedulerMsg {
Immediate(ScopeId),
/// A task has woken and needs to be progressed
TaskNotified(TaskId),
TaskNotified(Task),
}
use std::{cell::RefCell, rc::Rc};
+30 -7
View File
@@ -1,6 +1,7 @@
use futures_util::task::ArcWake;
use super::{Scheduler, SchedulerMsg};
use crate::innerlude::{push_future, remove_future};
use crate::ScopeId;
use std::cell::RefCell;
use std::future::Future;
@@ -14,7 +15,29 @@ use std::task::Waker;
/// once a Task has been completed.
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct TaskId(pub usize);
pub struct Task(pub(crate) usize);
impl Task {
/// Start a new future on the same thread as the rest of the VirtualDom.
///
/// This future will not contribute to suspense resolving, so you should primarily use this for reacting to changes
/// and long running tasks.
///
/// Whenever the component that owns this future is dropped, the future will be dropped as well.
///
/// Spawning a future onto the root scope will cause it to be dropped when the root component is dropped - which
/// will only occur when the VirtualDom itself has been dropped.
pub fn new(task: impl Future<Output = ()> + 'static) -> Self {
push_future(task).expect("to be in a dioxus runtime")
}
/// Drop the task immediately.
///
/// This does not abort the task, so you'll want to wrap it in an abort handle if that's important to you
pub fn stop(self) {
remove_future(self);
}
}
/// the task itself is the waker
pub(crate) struct LocalTask {
@@ -32,12 +55,12 @@ impl Scheduler {
/// Whenever the component that owns this future is dropped, the future will be dropped as well.
///
/// Spawning a future onto the root scope will cause it to be dropped when the root component is dropped - which
/// will only occur when the VirtuaalDom itself has been dropped.
pub fn spawn(&self, scope: ScopeId, task: impl Future<Output = ()> + 'static) -> TaskId {
/// will only occur when the VirtualDom itself has been dropped.
pub fn spawn(&self, scope: ScopeId, task: impl Future<Output = ()> + 'static) -> Task {
let mut tasks = self.tasks.borrow_mut();
let entry = tasks.vacant_entry();
let task_id = TaskId(entry.key());
let task_id = Task(entry.key());
let task = LocalTask {
task: RefCell::new(Box::pin(task)),
@@ -63,14 +86,14 @@ impl Scheduler {
/// Drop the future with the given TaskId
///
/// This does not abort the task, so you'll want to wrap it in an aborthandle if that's important to you
pub fn remove(&self, id: TaskId) -> Option<LocalTask> {
/// This does not abort the task, so you'll want to wrap it in an abort handle if that's important to you
pub fn remove(&self, id: Task) -> Option<LocalTask> {
self.tasks.borrow_mut().try_remove(id.0)
}
}
pub struct LocalTaskHandle {
id: TaskId,
id: Task,
tx: futures_channel::mpsc::UnboundedSender<SchedulerMsg>,
}
+2 -2
View File
@@ -1,4 +1,4 @@
use crate::{runtime::RuntimeGuard, TaskId, VirtualDom};
use crate::{runtime::RuntimeGuard, Task, VirtualDom};
use std::task::Context;
impl VirtualDom {
@@ -6,7 +6,7 @@ impl VirtualDom {
///
/// This is precise, meaning we won't poll every task, just tasks that have woken up as notified to use by the
/// queue
pub(crate) fn handle_task_wakeup(&mut self, id: TaskId) {
pub(crate) fn handle_task_wakeup(&mut self, id: Task) {
let _runtime = RuntimeGuard::new(self.runtime.clone());
let mut tasks = self.runtime.scheduler.tasks.borrow_mut();
+1 -1
View File
@@ -11,7 +11,7 @@ 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.get_scope(parent_id).map(|f| f.context().height + 1))
.and_then(|parent_id| self.runtime.get_context(parent_id).map(|f| f.height + 1))
.unwrap_or(0);
let entry = self.scopes.vacant_entry();
let id = ScopeId(entry.key());
+66 -139
View File
@@ -1,7 +1,7 @@
use crate::{
innerlude::{Scheduler, SchedulerMsg},
runtime::{with_current_scope, with_runtime},
Element, ScopeId, TaskId,
runtime::{with_runtime, with_scope},
Element, ScopeId, Task,
};
use rustc_hash::FxHashSet;
use std::{
@@ -9,7 +9,6 @@ use std::{
cell::{Cell, RefCell},
future::Future,
rc::Rc,
sync::Arc,
};
/// A component's state separate from its props.
@@ -32,7 +31,7 @@ pub(crate) struct ScopeContext {
pub(crate) hook_index: Cell<usize>,
pub(crate) tasks: Rc<Scheduler>,
pub(crate) spawned_tasks: RefCell<FxHashSet<TaskId>>,
pub(crate) spawned_tasks: RefCell<FxHashSet<Task>>,
}
impl ScopeContext {
@@ -62,42 +61,11 @@ impl ScopeContext {
self.parent_id
}
pub fn scope_id(&self) -> ScopeId {
self.id
}
/// Create a subscription that schedules a future render for the reference component
///
/// ## Notice: you should prefer using [`Self::schedule_update_any`] and [`Self::scope_id`]
pub fn schedule_update(&self) -> Arc<dyn Fn() + Send + Sync + 'static> {
let (chan, id) = (self.tasks.sender.clone(), self.scope_id());
Arc::new(move || drop(chan.unbounded_send(SchedulerMsg::Immediate(id))))
}
/// Schedule an update for any component given its [`ScopeId`].
///
/// A component's [`ScopeId`] can be obtained from `use_hook` or the [`ScopeState::scope_id`] method.
///
/// This method should be used when you want to schedule an update for a component
pub fn schedule_update_any(&self) -> Arc<dyn Fn(ScopeId) + Send + Sync> {
let chan = self.tasks.sender.clone();
Arc::new(move |id| {
chan.unbounded_send(SchedulerMsg::Immediate(id)).unwrap();
})
}
/// Mark this scope as dirty, and schedule a render for it.
pub fn needs_update(&self) {
self.needs_update_any(self.scope_id());
}
/// Get the [`ScopeId`] of a mounted component.
///
/// `ScopeId` is not unique for the lifetime of the [`crate::VirtualDom`] - a [`ScopeId`] will be reused if a component is unmounted.
pub fn needs_update_any(&self, id: ScopeId) {
self.tasks
.sender
.unbounded_send(SchedulerMsg::Immediate(id))
.unbounded_send(SchedulerMsg::Immediate(self.id))
.expect("Scheduler to exist if scope exists");
}
@@ -221,7 +189,7 @@ impl ScopeContext {
}
/// Pushes the future onto the poll queue to be polled after the component renders.
pub fn push_future(&self, fut: impl Future<Output = ()> + 'static) -> TaskId {
pub fn push_future(&self, fut: impl Future<Output = ()> + 'static) -> Task {
let id = self.tasks.spawn(self.id, fut);
self.spawned_tasks.borrow_mut().insert(id);
id
@@ -235,7 +203,7 @@ impl ScopeContext {
/// Spawn a future that Dioxus won't clean up when this component is unmounted
///
/// This is good for tasks that need to be run after the component has been dropped.
pub fn spawn_forever(&self, fut: impl Future<Output = ()> + 'static) -> TaskId {
pub fn spawn_forever(&self, fut: impl Future<Output = ()> + 'static) -> Task {
// The root scope will never be unmounted so we can just add the task at the top of the app
self.tasks.spawn(ScopeId::ROOT, fut)
}
@@ -243,7 +211,7 @@ impl ScopeContext {
/// Informs the scheduler that this task is no longer needed and should be removed.
///
/// This drops the task immediately.
pub fn remove_future(&self, id: TaskId) {
pub fn remove_future(&self, id: Task) {
self.tasks.remove(id);
}
@@ -317,115 +285,74 @@ impl Drop for ScopeContext {
}
}
/// Schedule an update for any component given its [`ScopeId`].
///
/// A component's [`ScopeId`] can be obtained from `use_hook` or the [`crate::scopes::ScopeState::scope_id`] method.
///
/// This method should be used when you want to schedule an update for a component
pub fn schedule_update_any() -> Option<Arc<dyn Fn(ScopeId) + Send + Sync>> {
with_current_scope(|cx| cx.schedule_update_any())
}
impl ScopeId {
/// Get the current scope id
pub fn current_scope_id(self) -> Option<ScopeId> {
with_runtime(|rt| rt.current_scope_id()).flatten()
}
/// Get the current scope id
pub fn current_scope_id() -> Option<ScopeId> {
with_runtime(|rt| rt.current_scope_id()).flatten()
}
#[doc(hidden)]
/// Check if the virtual dom is currently inside of the body of a component
pub fn vdom_is_rendering(self) -> bool {
with_runtime(|rt| rt.rendering.get()).unwrap_or_default()
}
#[doc(hidden)]
/// Check if the virtual dom is currently inside of the body of a component
pub fn vdom_is_rendering() -> bool {
with_runtime(|rt| rt.rendering.get()).unwrap_or_default()
}
/// Consume context from the current scope
pub fn consume_context<T: 'static + Clone>(self) -> Option<T> {
with_scope(self, |cx| cx.consume_context::<T>()).flatten()
}
/// Consume context from the current scope
pub fn consume_context<T: 'static + Clone>() -> Option<T> {
with_current_scope(|cx| cx.consume_context::<T>()).flatten()
}
/// Consume context from the current scope
pub fn consume_context_from_scope<T: 'static + Clone>(self, scope_id: ScopeId) -> Option<T> {
with_runtime(|rt| {
rt.get_context(scope_id)
.and_then(|cx| cx.consume_context::<T>())
})
.flatten()
}
/// Consume context from the current scope
pub fn consume_context_from_scope<T: 'static + Clone>(scope_id: ScopeId) -> Option<T> {
with_runtime(|rt| {
rt.get_context(scope_id)
.and_then(|cx| cx.consume_context::<T>())
})
.flatten()
}
/// Check if the current scope has a context
pub fn has_context<T: 'static + Clone>(self) -> Option<T> {
with_scope(self, |cx| cx.has_context::<T>()).flatten()
}
/// Check if the current scope has a context
pub fn has_context<T: 'static + Clone>() -> Option<T> {
with_current_scope(|cx| cx.has_context::<T>()).flatten()
}
/// Provide context to the current scope
pub fn provide_context<T: 'static + Clone>(self, value: T) -> Option<T> {
with_scope(self, |cx| cx.provide_context(value))
}
/// Provide context to the current scope
pub fn provide_context<T: 'static + Clone>(value: T) -> Option<T> {
with_current_scope(|cx| cx.provide_context(value))
}
/// Suspends the current component
pub fn suspend(self) -> Option<Element> {
with_scope(self, |cx| {
cx.suspend();
});
None
}
/// Provide context to the the given scope
pub fn provide_context_to_scope<T: 'static + Clone>(scope_id: ScopeId, value: T) -> Option<T> {
with_runtime(|rt| rt.get_context(scope_id).map(|cx| cx.provide_context(value))).flatten()
}
/// Pushes the future onto the poll queue to be polled after the component renders.
pub fn push_future(self, fut: impl Future<Output = ()> + 'static) -> Option<Task> {
with_scope(self, |cx| cx.push_future(fut))
}
/// Provide a context to the root scope
pub fn provide_root_context<T: 'static + Clone>(value: T) -> Option<T> {
with_current_scope(|cx| cx.provide_root_context(value))
}
/// Spawns the future but does not return the [`TaskId`]
pub fn spawn(self, fut: impl Future<Output = ()> + 'static) {
with_scope(self, |cx| cx.spawn(fut));
}
/// Suspends the current component
pub fn suspend() -> Option<Element> {
with_current_scope(|cx| {
cx.suspend();
});
None
}
/// Get the current render since the inception of this component
///
/// This can be used as a helpful diagnostic when debugging hooks/renders, etc
pub fn generation(self) -> Option<usize> {
with_scope(self, |cx| Some(cx.generation())).expect("to be in a dioxus runtime")
}
/// Pushes the future onto the poll queue to be polled after the component renders.
pub fn push_future(fut: impl Future<Output = ()> + 'static) -> Option<TaskId> {
with_current_scope(|cx| cx.push_future(fut))
}
/// Get the parent of the current scope if it exists
pub fn parent_scope(self) -> Option<ScopeId> {
with_scope(self, |cx| cx.parent_id()).flatten()
}
/// Spawns the future but does not return the [`TaskId`]
pub fn spawn(fut: impl Future<Output = ()> + 'static) {
with_current_scope(|cx| cx.spawn(fut));
}
/// Spawn a future that Dioxus won't clean up when this component is unmounted
///
/// This is good for tasks that need to be run after the component has been dropped.
pub fn spawn_forever(fut: impl Future<Output = ()> + 'static) -> Option<TaskId> {
with_current_scope(|cx| cx.spawn_forever(fut))
}
/// Informs the scheduler that this task is no longer needed and should be removed.
///
/// This drops the task immediately.
pub fn remove_future(id: TaskId) {
with_current_scope(|cx| cx.remove_future(id));
}
/// Store a value between renders. The foundational hook for all other hooks.
///
/// Accepts an `initializer` closure, which is run on the first use of the hook (typically the initial render). The return value of this closure is stored for the lifetime of the component, and a mutable reference to it is provided on every render as the return value of `use_hook`.
///
/// When the component is unmounted (removed from the UI), the value is dropped. This means you can return a custom type and provide cleanup code by implementing the [`Drop`] trait
///
/// # Example
///
/// ```
/// use dioxus_core::ScopeState;
///
/// // prints a greeting on the initial render
/// pub fn use_hello_world() {
/// once(|| println!("Hello, world!"));
/// }
/// ```
pub fn once<State: Clone + 'static>(initializer: impl FnOnce() -> State) -> State {
with_current_scope(|cx| cx.use_hook(initializer)).expect("to be in a dioxus runtime")
}
/// Get the current render since the inception of this component
///
/// This can be used as a helpful diagnostic when debugging hooks/renders, etc
pub fn generation() -> Option<usize> {
with_current_scope(|cx| Some(cx.generation())).expect("to be in a dioxus runtime")
/// Mark the current scope as dirty, causing it to re-render
pub fn needs_update(self) {
with_scope(self, |cx| cx.needs_update());
}
}
+2 -2
View File
@@ -10,7 +10,7 @@ use std::{cell::Ref, fmt::Debug, rc::Rc};
/// time for any logic that relies on these IDs to properly update.
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
pub struct ScopeId(pub usize);
pub struct ScopeId(pub(crate) usize);
impl ScopeId {
/// The root ScopeId.
@@ -30,7 +30,7 @@ impl ScopeId {
/// A component's state separate from its props.
///
/// This struct exists to provide a common interface for all scopes without relying on generics.
pub struct ScopeState {
pub(crate) struct ScopeState {
pub(crate) runtime: Rc<Runtime>,
pub(crate) context_id: ScopeId,
+10 -7
View File
@@ -18,7 +18,7 @@ use crate::{
use futures_util::{pin_mut, StreamExt};
use rustc_hash::{FxHashMap, FxHashSet};
use slab::Slab;
use std::{any::Any, cell::Cell, collections::BTreeSet, future::Future, rc::Rc, sync::Arc};
use std::{any::Any, cell::Cell, collections::BTreeSet, future::Future, rc::Rc};
/// A virtual node system that progresses user events and diffs UI trees.
///
@@ -277,10 +277,7 @@ impl VirtualDom {
// Unlike react, we provide a default error boundary that just renders the error as a string
root.context()
.provide_context(Rc::new(ErrorBoundary::new_in_scope(
ScopeId::ROOT,
Arc::new(|_| {}),
)));
.provide_context(Rc::new(ErrorBoundary::new_in_scope(ScopeId::ROOT)));
// the root element is always given element ID 0 since it's the container for the entire tree
dom.elements.insert(None);
@@ -291,17 +288,23 @@ impl VirtualDom {
/// Get the state for any scope given its ID
///
/// This is useful for inserting or removing contexts from a scope, or rendering out its root node
pub fn get_scope(&self, id: ScopeId) -> Option<&ScopeState> {
pub(crate) fn get_scope(&self, id: ScopeId) -> Option<&ScopeState> {
self.scopes.get(id.0).map(|s| &**s)
}
/// Get the single scope at the top of the VirtualDom tree that will always be around
///
/// This scope has a ScopeId of 0 and is the root of the tree
pub fn base_scope(&self) -> &ScopeState {
pub(crate) fn base_scope(&self) -> &ScopeState {
self.get_scope(ScopeId::ROOT).unwrap()
}
/// Run a closure inside the dioxus runtime
pub fn in_runtime<O>(&self, f: impl FnOnce() -> O) -> O {
let _runtime = RuntimeGuard::new(self.runtime.clone());
f()
}
/// Build the virtualdom with a global context inserted into the base scope
///
/// This is useful for what is essentially dependency injection when building the app