|
@@ -586,13 +586,58 @@ impl Scope {
|
|
pub(crate) fn root<'a>(&'a self) -> &'a VNode<'a> {
|
|
pub(crate) fn root<'a>(&'a self) -> &'a VNode<'a> {
|
|
&self.frames.cur_frame().head_node
|
|
&self.frames.cur_frame().head_node
|
|
}
|
|
}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/// Components in Dioxus use the "Context" object to interact with their lifecycle.
|
|
|
|
+/// This lets components schedule updates, integrate hooks, and expose their context via the context api.
|
|
|
|
+///
|
|
|
|
+/// Properties passed down from the parent component are also directly accessible via the exposed "props" field.
|
|
|
|
+///
|
|
|
|
+/// ```ignore
|
|
|
|
+/// #[derive(Properties)]
|
|
|
|
+/// struct Props {
|
|
|
|
+/// name: String
|
|
|
|
+///
|
|
|
|
+/// }
|
|
|
|
+///
|
|
|
|
+/// fn example(cx: Context<Props>) -> VNode {
|
|
|
|
+/// html! {
|
|
|
|
+/// <div> "Hello, {cx.name}" </div>
|
|
|
|
+/// }
|
|
|
|
+/// }
|
|
|
|
+/// ```
|
|
|
|
+// todo: force lifetime of source into T as a valid lifetime too
|
|
|
|
+// it's definitely possible, just needs some more messing around
|
|
|
|
+pub struct Context<'src, T> {
|
|
|
|
+ pub props: &'src T,
|
|
|
|
+ pub scope: &'src Scope,
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<'src, T> Copy for Context<'src, T> {}
|
|
|
|
+impl<'src, T> Clone for Context<'src, T> {
|
|
|
|
+ fn clone(&self) -> Self {
|
|
|
|
+ Self {
|
|
|
|
+ props: self.props,
|
|
|
|
+ scope: self.scope,
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<'a, T> Deref for Context<'a, T> {
|
|
|
|
+ type Target = &'a T;
|
|
|
|
+
|
|
|
|
+ fn deref(&self) -> &Self::Target {
|
|
|
|
+ &self.props
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
|
|
+impl<'src, P> Context<'src, P> {
|
|
/// Access the children elements passed into the component
|
|
/// Access the children elements passed into the component
|
|
- pub fn children(&self) -> &[VNode] {
|
|
|
|
|
|
+ pub fn children(&self) -> &'src [VNode<'src>] {
|
|
// We're re-casting the nodes back out
|
|
// We're re-casting the nodes back out
|
|
// They don't really have a static lifetime
|
|
// They don't really have a static lifetime
|
|
unsafe {
|
|
unsafe {
|
|
- let scope = self;
|
|
|
|
|
|
+ let scope = self.scope;
|
|
let nodes = scope.child_nodes;
|
|
let nodes = scope.child_nodes;
|
|
nodes
|
|
nodes
|
|
}
|
|
}
|
|
@@ -600,7 +645,7 @@ impl Scope {
|
|
|
|
|
|
/// Create a subscription that schedules a future render for the reference component
|
|
/// Create a subscription that schedules a future render for the reference component
|
|
pub fn schedule_update(&self) -> Rc<dyn Fn() + 'static> {
|
|
pub fn schedule_update(&self) -> Rc<dyn Fn() + 'static> {
|
|
- self.event_channel.clone()
|
|
|
|
|
|
+ self.scope.event_channel.clone()
|
|
}
|
|
}
|
|
|
|
|
|
pub fn schedule_effect(&self) -> Rc<dyn Fn() + 'static> {
|
|
pub fn schedule_effect(&self) -> Rc<dyn Fn() + 'static> {
|
|
@@ -626,11 +671,11 @@ impl Scope {
|
|
/// cx.render(lazy_tree)
|
|
/// cx.render(lazy_tree)
|
|
/// }
|
|
/// }
|
|
///```
|
|
///```
|
|
- pub fn render<'src, F: FnOnce(NodeFactory<'src>) -> VNode<'src>>(
|
|
|
|
- &'src self,
|
|
|
|
|
|
+ pub fn render<F: FnOnce(NodeFactory<'src>) -> VNode<'src>>(
|
|
|
|
+ self,
|
|
lazy_nodes: LazyNodes<'src, F>,
|
|
lazy_nodes: LazyNodes<'src, F>,
|
|
) -> VNode<'src> {
|
|
) -> VNode<'src> {
|
|
- let scope_ref = self;
|
|
|
|
|
|
+ let scope_ref = self.scope;
|
|
let listener_id = &scope_ref.listener_idx;
|
|
let listener_id = &scope_ref.listener_idx;
|
|
lazy_nodes.into_vnode(NodeFactory {
|
|
lazy_nodes.into_vnode(NodeFactory {
|
|
scope_ref,
|
|
scope_ref,
|
|
@@ -654,8 +699,8 @@ impl Scope {
|
|
/// )
|
|
/// )
|
|
/// }
|
|
/// }
|
|
/// ```
|
|
/// ```
|
|
- pub fn use_hook<'src, InternalHookState: 'static, Output: 'src>(
|
|
|
|
- &'src self,
|
|
|
|
|
|
+ pub fn use_hook<InternalHookState: 'static, Output: 'src>(
|
|
|
|
+ self,
|
|
|
|
|
|
// The closure that builds the hook state
|
|
// The closure that builds the hook state
|
|
initializer: impl FnOnce() -> InternalHookState,
|
|
initializer: impl FnOnce() -> InternalHookState,
|
|
@@ -667,7 +712,7 @@ impl Scope {
|
|
// TODO: add this to the "clean up" group for when the component is dropped
|
|
// TODO: add this to the "clean up" group for when the component is dropped
|
|
_cleanup: impl FnOnce(InternalHookState),
|
|
_cleanup: impl FnOnce(InternalHookState),
|
|
) -> Output {
|
|
) -> Output {
|
|
- let scope = self;
|
|
|
|
|
|
+ let scope = self.scope;
|
|
|
|
|
|
let idx = scope.hookidx.get();
|
|
let idx = scope.hookidx.get();
|
|
|
|
|
|
@@ -715,8 +760,8 @@ Any function prefixed with "use" should not be called conditionally.
|
|
///
|
|
///
|
|
///
|
|
///
|
|
///
|
|
///
|
|
- fn use_create_context<T: 'static>(&self, init: impl Fn() -> T) {
|
|
|
|
- let scope = self;
|
|
|
|
|
|
+ pub fn use_create_context<T: 'static>(&self, init: impl Fn() -> T) {
|
|
|
|
+ let mut scope = self.scope;
|
|
let mut cxs = scope.shared_contexts.borrow_mut();
|
|
let mut cxs = scope.shared_contexts.borrow_mut();
|
|
let ty = TypeId::of::<T>();
|
|
let ty = TypeId::of::<T>();
|
|
|
|
|
|
@@ -745,12 +790,12 @@ Any function prefixed with "use" should not be called conditionally.
|
|
}
|
|
}
|
|
|
|
|
|
/// There are hooks going on here!
|
|
/// There are hooks going on here!
|
|
- pub fn use_context<'src, T: 'static>(&'src self) -> &'src Rc<T> {
|
|
|
|
|
|
+ pub fn use_context<T: 'static>(self) -> &'src Rc<T> {
|
|
self.try_use_context().unwrap()
|
|
self.try_use_context().unwrap()
|
|
}
|
|
}
|
|
|
|
|
|
/// Uses a context, storing the cached value around
|
|
/// Uses a context, storing the cached value around
|
|
- pub fn try_use_context<'src, T: 'static>(&'src self) -> Result<&'src Rc<T>> {
|
|
|
|
|
|
+ pub fn try_use_context<T: 'static>(self) -> Result<&'src Rc<T>> {
|
|
struct UseContextHook<C> {
|
|
struct UseContextHook<C> {
|
|
par: Option<Rc<C>>,
|
|
par: Option<Rc<C>>,
|
|
we: Option<Weak<C>>,
|
|
we: Option<Weak<C>>,
|
|
@@ -762,7 +807,7 @@ Any function prefixed with "use" should not be called conditionally.
|
|
we: None as Option<Weak<T>>,
|
|
we: None as Option<Weak<T>>,
|
|
},
|
|
},
|
|
move |hook| {
|
|
move |hook| {
|
|
- let mut scope = Some(self);
|
|
|
|
|
|
+ let mut scope = Some(self.scope);
|
|
|
|
|
|
if let Some(we) = &hook.we {
|
|
if let Some(we) = &hook.we {
|
|
if let Some(re) = we.upgrade() {
|
|
if let Some(re) = we.upgrade() {
|
|
@@ -807,11 +852,7 @@ Any function prefixed with "use" should not be called conditionally.
|
|
)
|
|
)
|
|
}
|
|
}
|
|
|
|
|
|
- pub fn suspend<
|
|
|
|
- 'src,
|
|
|
|
- Output: 'src,
|
|
|
|
- Fut: FnOnce(SuspendedContext, Output) -> VNode<'src> + 'src,
|
|
|
|
- >(
|
|
|
|
|
|
+ pub fn suspend<Output: 'src, Fut: FnOnce(SuspendedContext, Output) -> VNode<'src> + 'src>(
|
|
&'src self,
|
|
&'src self,
|
|
fut: &'src mut Pin<Box<dyn Future<Output = Output> + 'static>>,
|
|
fut: &'src mut Pin<Box<dyn Future<Output = Output> + 'static>>,
|
|
callback: Fut,
|
|
callback: Fut,
|
|
@@ -832,120 +873,6 @@ Any function prefixed with "use" should not be called conditionally.
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-/// Components in Dioxus use the "Context" object to interact with their lifecycle.
|
|
|
|
-/// This lets components schedule updates, integrate hooks, and expose their context via the context api.
|
|
|
|
-///
|
|
|
|
-/// Properties passed down from the parent component are also directly accessible via the exposed "props" field.
|
|
|
|
-///
|
|
|
|
-/// ```ignore
|
|
|
|
-/// #[derive(Properties)]
|
|
|
|
-/// struct Props {
|
|
|
|
-/// name: String
|
|
|
|
-///
|
|
|
|
-/// }
|
|
|
|
-///
|
|
|
|
-/// fn example(cx: Context<Props>) -> VNode {
|
|
|
|
-/// html! {
|
|
|
|
-/// <div> "Hello, {cx.name}" </div>
|
|
|
|
-/// }
|
|
|
|
-/// }
|
|
|
|
-/// ```
|
|
|
|
-// todo: force lifetime of source into T as a valid lifetime too
|
|
|
|
-// it's definitely possible, just needs some more messing around
|
|
|
|
-pub struct Context<'src, T> {
|
|
|
|
- pub props: &'src T,
|
|
|
|
- pub scope: &'src Scope,
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-impl<'src, T> Copy for Context<'src, T> {}
|
|
|
|
-impl<'src, T> Clone for Context<'src, T> {
|
|
|
|
- fn clone(&self) -> Self {
|
|
|
|
- Self {
|
|
|
|
- props: self.props,
|
|
|
|
- scope: self.scope,
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-impl<'a, T> Deref for Context<'a, T> {
|
|
|
|
- type Target = &'a T;
|
|
|
|
-
|
|
|
|
- fn deref(&self) -> &Self::Target {
|
|
|
|
- &self.props
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-/// The `Scoped` trait makes it slightly less cumbersome for hooks to use the underlying `Scope` without having to make
|
|
|
|
-/// their hooks generic over the [`Props`] type that [`Context`] is
|
|
|
|
-///
|
|
|
|
-/// ## Example:
|
|
|
|
-///
|
|
|
|
-/// ```
|
|
|
|
-/// fn use_raw<T>(cx: impl Scoped) -> &mut T {
|
|
|
|
-///
|
|
|
|
-/// }
|
|
|
|
-/// ```
|
|
|
|
-///
|
|
|
|
-pub trait Scoped<'src>: Sized + Clone + Copy {
|
|
|
|
- ///
|
|
|
|
- ///
|
|
|
|
- ///
|
|
|
|
- ///
|
|
|
|
- ///
|
|
|
|
- ///
|
|
|
|
- ///
|
|
|
|
- fn get_scope(self) -> &'src Scope;
|
|
|
|
-
|
|
|
|
- #[inline]
|
|
|
|
- fn children(self) -> &'src [VNode<'src>] {
|
|
|
|
- self.get_scope().children()
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- #[inline]
|
|
|
|
- fn schedule_update(self) -> Rc<dyn Fn() + 'static> {
|
|
|
|
- self.get_scope().schedule_update()
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- #[inline]
|
|
|
|
- fn use_hook<InternalHookState: 'static, Output: 'src>(
|
|
|
|
- self,
|
|
|
|
- initializer: impl FnOnce() -> InternalHookState,
|
|
|
|
- runner: impl FnOnce(&'src mut InternalHookState) -> Output,
|
|
|
|
- _cleanup: impl FnOnce(InternalHookState),
|
|
|
|
- ) -> Output {
|
|
|
|
- self.get_scope().use_hook(initializer, runner, _cleanup)
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /// Take a lazy VNode structure and actually build it with the context of the VDom's efficient VNode allocator.
|
|
|
|
- ///
|
|
|
|
- /// This function consumes the context and absorb the lifetime, so these VNodes *must* be returned.
|
|
|
|
- ///
|
|
|
|
- /// ## Example
|
|
|
|
- ///
|
|
|
|
- /// ```ignore
|
|
|
|
- /// fn Component(cx: Context<()>) -> VNode {
|
|
|
|
- /// // Lazy assemble the VNode tree
|
|
|
|
- /// let lazy_tree = html! {<div> "Hello World" </div>};
|
|
|
|
- ///
|
|
|
|
- /// // Actually build the tree and allocate it
|
|
|
|
- /// cx.render(lazy_tree)
|
|
|
|
- /// }
|
|
|
|
- ///```
|
|
|
|
- #[inline]
|
|
|
|
- fn render<F: FnOnce(NodeFactory<'src>) -> VNode<'src>>(
|
|
|
|
- self,
|
|
|
|
- lazy_nodes: LazyNodes<'src, F>,
|
|
|
|
- ) -> VNode<'src> {
|
|
|
|
- self.get_scope().render(lazy_nodes)
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-impl<'src, T> Scoped<'src> for Context<'src, T> {
|
|
|
|
- #[inline]
|
|
|
|
- fn get_scope(self) -> &'src Scope {
|
|
|
|
- self.scope
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
#[derive(Clone)]
|
|
#[derive(Clone)]
|
|
pub struct SuspendedContext {}
|
|
pub struct SuspendedContext {}
|
|
|
|
|