wip: move children onto scope

This commit is contained in:
Jonathan Kelley 2021-11-01 03:49:32 -04:00
parent d1b294fff0
commit f438bbcfd2
6 changed files with 85 additions and 19 deletions

View file

@ -37,7 +37,7 @@ once_cell = "1.8.0"
indexmap = "1.7.0" indexmap = "1.7.0"
# # Serialize the Edits for use in Webview/Liveview instances # Serialize the Edits for use in Webview/Liveview instances
serde = { version = "1", features = ["derive"], optional = true } serde = { version = "1", features = ["derive"], optional = true }
serde_repr = { version = "0.1.7", optional = true } serde_repr = { version = "0.1.7", optional = true }

View file

@ -66,15 +66,15 @@ pub(crate) mod innerlude {
pub use crate::innerlude::{ pub use crate::innerlude::{
Context, DioxusElement, DomEdit, Element, ElementId, EventPriority, MountType, Mutations, Context, DioxusElement, DomEdit, Element, ElementId, EventPriority, MountType, Mutations,
NodeFactory, Properties, SchedulerMsg, ScopeId, SuspendedContext, TaskHandle, TestDom, NodeFactory, Properties, SchedulerMsg, ScopeChildren, ScopeId, SuspendedContext, TaskHandle,
ThreadsafeVirtualDom, UserEvent, VNode, VirtualDom, FC, TestDom, ThreadsafeVirtualDom, UserEvent, VNode, VirtualDom, FC,
}; };
pub mod prelude { pub mod prelude {
pub use crate::component::{fc_to_builder, Fragment, Properties, Scope}; pub use crate::component::{fc_to_builder, Fragment, Properties, Scope};
pub use crate::context::Context; pub use crate::context::Context;
pub use crate::hooks::*; pub use crate::hooks::*;
pub use crate::innerlude::{DioxusElement, Element, LazyNodes, NodeFactory, FC}; pub use crate::innerlude::{DioxusElement, Element, LazyNodes, NodeFactory, ScopeChildren, FC};
pub use crate::nodes::VNode; pub use crate::nodes::VNode;
pub use crate::VirtualDom; pub use crate::VirtualDom;
} }

View file

@ -726,3 +726,65 @@ impl IntoVNode<'_> for Arguments<'_> {
cx.text(self) cx.text(self)
} }
} }
/// Access the children elements passed into the component
///
/// This enables patterns where a component is passed children from its parent.
///
/// ## Details
///
/// Unlike React, Dioxus allows *only* lists of children to be passed from parent to child - not arbitrary functions
/// or classes. If you want to generate nodes instead of accepting them as a list, consider declaring a closure
/// on the props that takes Context.
///
/// If a parent passes children into a component, the child will always re-render when the parent re-renders. In other
/// words, a component cannot be automatically memoized if it borrows nodes from its parent, even if the component's
/// props are valid for the static lifetime.
///
/// ## Example
///
/// ```rust
/// const App: FC<()> = |(cx, props)|{
/// cx.render(rsx!{
/// CustomCard {
/// h1 {}
/// p {}
/// }
/// })
/// }
///
/// const CustomCard: FC<()> = |(cx, props)|{
/// cx.render(rsx!{
/// div {
/// h1 {"Title card"}
/// {props.children}
/// }
/// })
/// }
/// ```
///
/// ## Notes:
///
/// This method returns a "ScopeChildren" object. This object is copy-able and preserve the correct lifetime.
pub struct ScopeChildren<'a> {
root: Option<VNode<'a>>,
}
impl IntoIterator for &ScopeChildren<'_> {
type Item = Self;
type IntoIter = std::iter::Once<Self>;
fn into_iter(self) -> Self::IntoIter {
todo!()
}
}
impl<'a> IntoVNode<'a> for &ScopeChildren<'a> {
fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
match &self.root {
Some(n) => n.decouple(),
None => cx.fragment_from_iter(None as Option<VNode>),
}
}
}

View file

@ -340,8 +340,6 @@ impl ScopeInner {
let render: &dyn for<'b> Fn(&'b ScopeInner) -> Element<'b> = unsafe { &*self.caller }; let render: &dyn for<'b> Fn(&'b ScopeInner) -> Element<'b> = unsafe { &*self.caller };
// Todo: see if we can add stronger guarantees around internal bookkeeping and failed component renders. // Todo: see if we can add stronger guarantees around internal bookkeeping and failed component renders.
//
// todo!()
if let Some(builder) = render(self) { if let Some(builder) = render(self) {
let new_head = builder.into_vnode(NodeFactory { let new_head = builder.into_vnode(NodeFactory {
bump: &self.frames.wip_frame().bump, bump: &self.frames.wip_frame().bump,

View file

@ -64,10 +64,10 @@ fn create() {
"Hello, world!" "Hello, world!"
div { div {
div { div {
Fragment { // Fragment {
"hello" // "hello"
"world" // "world"
} // }
} }
} }
} }
@ -208,20 +208,26 @@ fn create_simple() {
#[test] #[test]
fn create_components() { fn create_components() {
static App: FC<()> = |(cx, props)| { static App: FC<()> = |(cx, props)| {
cx.render(rsx! { todo!()
Child { "abc1" } // cx.render(rsx! {
Child { "abc2" } // Child { "abc1" }
Child { "abc3" } // Child { "abc2" }
}) // Child { "abc3" }
// })
}; };
static Child: FC<()> = |(cx, props)| { #[derive(Props)]
struct ChildProps<'a> {
children: ScopeChildren<'a>,
}
fn Child<'a>((cx, props): Scope<'a, ChildProps<'a>>) -> Element {
cx.render(rsx! { cx.render(rsx! {
h1 {} h1 {}
div { {cx.children()} } div { {&props.children} }
p {} p {}
}) })
}; }
let mut dom = new_dom(App, ()); let mut dom = new_dom(App, ());
let mutations = dom.rebuild(); let mutations = dom.rebuild();

View file

@ -1,6 +1,6 @@
#![allow(unused, non_upper_case_globals)] #![allow(unused, non_upper_case_globals)]
use dioxus::{prelude::*, DomEdit, TestDom}; use dioxus::{prelude::*, DomEdit, Mutations, TestDom};
use dioxus_core as dioxus; use dioxus_core as dioxus;
use dioxus_core_macro::*; use dioxus_core_macro::*;
use dioxus_html as dioxus_elements; use dioxus_html as dioxus_elements;