mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-29 07:30:20 +00:00
fix: messed up how lifetimes worked, need to render once per component
This commit is contained in:
parent
0e9d5fc530
commit
ba9e1dbb8f
33 changed files with 323 additions and 184 deletions
|
@ -20,7 +20,7 @@ fn main() {
|
|||
dioxus::desktop::launch(App, |c| c);
|
||||
}
|
||||
|
||||
fn App((cx, props): Component<()>) -> Element {
|
||||
fn App((cx, props): Scope<()>) -> Element {
|
||||
let text: &mut Vec<String> = cx.use_hook(|_| vec![String::from("abc=def")], |f| f, |_| {});
|
||||
|
||||
let first = text.get_mut(0).unwrap();
|
||||
|
@ -43,7 +43,7 @@ impl<'a> Drop for C1Props<'a> {
|
|||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
fn Child1<'a>((cx, props): Component<'a, C1Props>) -> Element<'a> {
|
||||
fn Child1<'a>((cx, props): Scope<'a, C1Props>) -> Element<'a> {
|
||||
let (left, right) = props.text.split_once("=").unwrap();
|
||||
|
||||
cx.render(rsx! {
|
||||
|
@ -59,7 +59,7 @@ struct C2Props<'a> {
|
|||
text: &'a str,
|
||||
}
|
||||
|
||||
fn Child2<'a>((cx, props): Component<'a, C2Props>) -> Element<'a> {
|
||||
fn Child2<'a>((cx, props): Scope<'a, C2Props>) -> Element<'a> {
|
||||
cx.render(rsx! {
|
||||
Child3 {
|
||||
text: props.text
|
||||
|
@ -72,7 +72,7 @@ struct C3Props<'a> {
|
|||
text: &'a str,
|
||||
}
|
||||
|
||||
fn Child3<'a>((cx, props): Component<'a, C3Props>) -> Element<'a> {
|
||||
fn Child3<'a>((cx, props): Scope<'a, C3Props>) -> Element<'a> {
|
||||
cx.render(rsx! {
|
||||
div { "{props.text}"}
|
||||
})
|
||||
|
|
|
@ -116,7 +116,7 @@ struct CalculatorKeyProps<'a> {
|
|||
onclick: &'a dyn Fn(MouseEvent),
|
||||
}
|
||||
|
||||
fn CalculatorKey<'a>((cx, props): Component<'a, CalculatorKeyProps>) -> Element<'a> {
|
||||
fn CalculatorKey<'a>((cx, props): Scope<'a, CalculatorKeyProps>) -> Element<'a> {
|
||||
rsx!(cx, button {
|
||||
class: "calculator-key {props.name}"
|
||||
onclick: {props.onclick}
|
||||
|
|
|
@ -80,7 +80,7 @@ struct ActionButtonProps<'a> {
|
|||
onclick: &'a dyn Fn(MouseEvent),
|
||||
}
|
||||
|
||||
fn ActionButton<'a>((cx, props): Component<'a, ActionButtonProps>) -> Element<'a> {
|
||||
fn ActionButton<'a>((cx, props): Scope<'a, ActionButtonProps>) -> Element<'a> {
|
||||
rsx!(cx, div { class: "col-sm-6 smallpad"
|
||||
button { class:"btn btn-primary btn-block", r#type: "button", id: "{props.id}", onclick: {props.onclick},
|
||||
"{props.name}"
|
||||
|
@ -93,7 +93,7 @@ struct RowProps {
|
|||
row_id: usize,
|
||||
label: Rc<str>,
|
||||
}
|
||||
fn Row((cx, props): Component<RowProps>) -> Element {
|
||||
fn Row((cx, props): Scope<RowProps>) -> Element {
|
||||
rsx!(cx, tr {
|
||||
td { class:"col-md-1", "{props.row_id}" }
|
||||
td { class:"col-md-1", onclick: move |_| { /* run onselect */ }
|
||||
|
|
|
@ -4,7 +4,7 @@ fn main() {
|
|||
dioxus::desktop::launch(App, |c| c);
|
||||
}
|
||||
|
||||
fn App((cx, props): Component<()>) -> Element {
|
||||
fn App((cx, props): Scope<()>) -> Element {
|
||||
cx.render(rsx! (
|
||||
div { "Hello, world!" }
|
||||
))
|
||||
|
|
|
@ -76,7 +76,7 @@ struct CalculatorKeyProps<'a> {
|
|||
onclick: &'a dyn Fn(MouseEvent),
|
||||
}
|
||||
|
||||
fn CalculatorKey<'a>((cx, props): Component<'a, CalculatorKeyProps>) -> Element<'a> {
|
||||
fn CalculatorKey<'a>((cx, props): Scope<'a, CalculatorKeyProps>) -> Element<'a> {
|
||||
cx.render(rsx! {
|
||||
button {
|
||||
class: "calculator-key {props.name}"
|
||||
|
|
|
@ -184,7 +184,7 @@ mod baller {
|
|||
pub struct BallerProps {}
|
||||
|
||||
/// This component totally balls
|
||||
pub fn Baller(_: Component<BallerProps>) -> Element {
|
||||
pub fn Baller(_: Scope<BallerProps>) -> Element {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
@ -195,7 +195,7 @@ pub struct TallerProps {
|
|||
}
|
||||
|
||||
/// This component is taller than most :)
|
||||
pub fn Taller(_: Component<TallerProps>) -> Element {
|
||||
pub fn Taller(_: Scope<TallerProps>) -> Element {
|
||||
let b = true;
|
||||
todo!()
|
||||
}
|
||||
|
|
|
@ -85,7 +85,7 @@ pub struct TodoEntryProps {
|
|||
todo: Rc<TodoItem>,
|
||||
}
|
||||
|
||||
pub fn TodoEntry((cx, props): Component<TodoEntryProps>) -> Element {
|
||||
pub fn TodoEntry((cx, props): Scope<TodoEntryProps>) -> Element {
|
||||
let is_editing = use_state(cx, || false);
|
||||
let contents = use_state(cx, || String::from(""));
|
||||
let todo = &props.todo;
|
||||
|
|
|
@ -45,7 +45,7 @@ struct RowProps {
|
|||
row_id: usize,
|
||||
label: Label,
|
||||
}
|
||||
fn Row((cx, props): Component<RowProps>) -> Element {
|
||||
fn Row((cx, props): Scope<RowProps>) -> Element {
|
||||
let [adj, col, noun] = props.label.0;
|
||||
cx.render(rsx! {
|
||||
tr {
|
||||
|
|
|
@ -57,11 +57,11 @@ impl ToTokens for CallBody {
|
|||
}),
|
||||
// Otherwise we just build the LazyNode wrapper
|
||||
None => out_tokens.append_all(quote! {
|
||||
Some(dioxus::prelude::LazyNodes::new(move |__cx: NodeFactory|{
|
||||
dioxus::prelude::LazyNodes::new(move |__cx: NodeFactory|{
|
||||
use dioxus_elements::{GlobalAttributes, SvgAttributes};
|
||||
|
||||
#inner
|
||||
}))
|
||||
})
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
|
3
packages/core/.vscode/settings.json
vendored
3
packages/core/.vscode/settings.json
vendored
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"rust-analyzer.inlayHints.enable": true
|
||||
}
|
|
@ -42,8 +42,6 @@ serde = { version = "1", features = ["derive"], optional = true }
|
|||
|
||||
serde_repr = { version = "0.1.7", optional = true }
|
||||
|
||||
stack_dst = "0.6.1"
|
||||
|
||||
[dev-dependencies]
|
||||
anyhow = "1.0.42"
|
||||
dioxus-html = { path = "../html" }
|
||||
|
|
|
@ -34,13 +34,13 @@ fn create_rows(c: &mut Criterion) {
|
|||
}
|
||||
}
|
||||
});
|
||||
rsx! {
|
||||
cx.render(rsx! {
|
||||
table {
|
||||
tbody {
|
||||
{rows}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
c.bench_function("create rows", |b| {
|
||||
|
@ -57,9 +57,9 @@ struct RowProps {
|
|||
row_id: usize,
|
||||
label: Label,
|
||||
}
|
||||
fn Row((cx, props): Component<RowProps>) -> Element {
|
||||
fn Row((cx, props): Scope<RowProps>) -> Element {
|
||||
let [adj, col, noun] = props.label.0;
|
||||
rsx! {
|
||||
cx.render(rsx! {
|
||||
tr {
|
||||
td { class:"col-md-1", "{props.row_id}" }
|
||||
td { class:"col-md-1", onclick: move |_| { /* run onselect */ }
|
||||
|
@ -72,7 +72,7 @@ fn Row((cx, props): Component<RowProps>) -> Element {
|
|||
}
|
||||
td { class: "col-md-6" }
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
|
|
|
@ -9,7 +9,7 @@ fn main() {
|
|||
pub static EXAMPLE: FC<()> = |(cx, _)| {
|
||||
let list = (0..10).map(|_f| LazyNodes::new(move |_f| todo!()));
|
||||
|
||||
Some(LazyNodes::new(move |cx| {
|
||||
cx.render(LazyNodes::new(move |cx| {
|
||||
cx.raw_element(
|
||||
"div",
|
||||
None,
|
||||
|
|
|
@ -23,7 +23,7 @@ struct ListItem {
|
|||
fn app<'a>(cx: Context<'a>, props: &AppProps) -> Element<'a> {
|
||||
// let (val, set_val) = use_state_classic(cx, || 0);
|
||||
|
||||
Some(LazyNodes::new(move |_nodecx| {
|
||||
cx.render(LazyNodes::new(move |_nodecx| {
|
||||
todo!()
|
||||
// builder::ElementBuilder::new(_nodecx, "div")
|
||||
// .iter_child({
|
||||
|
@ -57,7 +57,7 @@ struct ChildProps {
|
|||
}
|
||||
|
||||
fn ChildItem<'a>(cx: Context<'a>, props: &'a ChildProps) -> Element<'a> {
|
||||
Some(LazyNodes::new(move |__cx| todo!()))
|
||||
cx.render(LazyNodes::new(move |__cx| todo!()))
|
||||
}
|
||||
|
||||
impl PartialEq for ChildProps {
|
||||
|
|
|
@ -26,7 +26,7 @@ fn app<'a>(cx: Context<'a>, props: &()) -> Element<'a> {
|
|||
)
|
||||
}));
|
||||
|
||||
Some(LazyNodes::new(move |f| {
|
||||
cx.render(LazyNodes::new(move |f| {
|
||||
f.raw_element(
|
||||
"div",
|
||||
None,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#![allow(non_snake_case)]
|
||||
|
||||
use dioxus::component::Component;
|
||||
use dioxus::component::Scope;
|
||||
use dioxus::events::on::MouseEvent;
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
|
@ -15,7 +15,7 @@ fn main() {
|
|||
assert!(g.edits.len() > 1);
|
||||
}
|
||||
|
||||
fn App((cx, props): Component<()>) -> Element {
|
||||
fn App((cx, props): Scope<()>) -> Element {
|
||||
let mut rng = SmallRng::from_entropy();
|
||||
let rows = (0..10_000_usize).map(|f| {
|
||||
let label = Label::new(&mut rng);
|
||||
|
@ -26,13 +26,13 @@ fn App((cx, props): Component<()>) -> Element {
|
|||
}
|
||||
}
|
||||
});
|
||||
rsx! {
|
||||
cx.render(rsx! {
|
||||
table {
|
||||
tbody {
|
||||
{rows}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Props)]
|
||||
|
@ -41,11 +41,11 @@ struct RowProps {
|
|||
label: Label,
|
||||
}
|
||||
|
||||
fn Row((cx, props): Component<RowProps>) -> Element {
|
||||
fn Row((cx, props): Scope<RowProps>) -> Element {
|
||||
let handler = move |evt: MouseEvent| {
|
||||
let g = evt.button;
|
||||
};
|
||||
rsx! {
|
||||
cx.render(rsx! {
|
||||
tr {
|
||||
td { class:"col-md-1", "{props.row_id}" }
|
||||
td { class:"col-md-1", onclick: move |_| { /* run onselect */ }
|
||||
|
@ -58,7 +58,7 @@ fn Row((cx, props): Component<RowProps>) -> Element {
|
|||
}
|
||||
td { class: "col-md-6" }
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
use dioxus::component::Component;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use dioxus::component::Scope;
|
||||
use dioxus::events::on::MouseEvent;
|
||||
use dioxus::nodes::{IntoVNode, IntoVNodeList};
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_core_macro::*;
|
||||
|
@ -20,20 +23,97 @@ fn html_usage() {
|
|||
|
||||
let items = ["bob", "bill", "jack"];
|
||||
|
||||
let f = items.iter().filter(|f| f.starts_with("b")).map(|f| {
|
||||
rsx! {
|
||||
"hello {f}"
|
||||
}
|
||||
});
|
||||
let f = items
|
||||
.iter()
|
||||
.filter(|f| f.starts_with('b'))
|
||||
.map(|f| rsx!("hello {f}"));
|
||||
|
||||
let p = rsx! {
|
||||
div {
|
||||
{f}
|
||||
}
|
||||
};
|
||||
let p = rsx!(div { {f} });
|
||||
}
|
||||
|
||||
static App2: FC<()> = |(cx, _)| cx.render(rsx!("hello world!"));
|
||||
|
||||
static App: FC<()> = |(cx, props)| {
|
||||
//
|
||||
rsx!(div {})
|
||||
let name = cx.use_state(|| 0);
|
||||
|
||||
cx.render(rsx!(div {
|
||||
h1 {}
|
||||
h2 {}
|
||||
}))
|
||||
};
|
||||
|
||||
pub trait UseState<'a, T: 'static> {
|
||||
fn use_state(self, f: impl FnOnce() -> T) -> &'a T;
|
||||
}
|
||||
impl<'a, T: 'static> UseState<'a, T> for Context<'a> {
|
||||
fn use_state(self, f: impl FnOnce() -> T) -> &'a T {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
fn App3((cx, props): Scope<()>) -> Element {
|
||||
let p = rsx! {
|
||||
Child {
|
||||
bame: 10,
|
||||
}
|
||||
};
|
||||
cx.render(rsx!(Child {
|
||||
bame: 102,
|
||||
..ChildProps { bame: 10 }
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(Props, PartialEq, Debug)]
|
||||
struct ChildProps {
|
||||
bame: i32, // children: Children<'a>,
|
||||
}
|
||||
|
||||
fn Child<'a>((cx, props): Scope<'a, ChildProps>) -> Element<'a> {
|
||||
cx.render(rsx!(div {
|
||||
// {props.children}
|
||||
}))
|
||||
}
|
||||
|
||||
// Some(LazyNodes::new(|f| {
|
||||
// //
|
||||
// // let r = f.fragment_from_iter(&props.children);
|
||||
// r
|
||||
// // todo!()
|
||||
// }))
|
||||
// todo!()
|
||||
// rsx!({ Some(p) })
|
||||
// todo!()
|
||||
|
||||
pub struct Children<'a> {
|
||||
children: VNode<'static>,
|
||||
_p: PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
impl<'a> Children<'a> {
|
||||
pub fn new(children: VNode<'a>) -> Self {
|
||||
Self {
|
||||
children: unsafe { std::mem::transmute(children) },
|
||||
_p: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'a> IntoVNodeList<'a> for &Children<'a> {
|
||||
fn into_vnode_list(self, cx: NodeFactory<'a>) -> &'a [VNode<'a>] {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
static Bapp: FC<()> = |(cx, props)| {
|
||||
let name = cx.use_state(|| 0);
|
||||
|
||||
cx.render(rsx!(
|
||||
div {
|
||||
div {
|
||||
|
||||
}
|
||||
div {
|
||||
|
||||
}
|
||||
}
|
||||
))
|
||||
};
|
||||
|
|
|
@ -4,7 +4,7 @@ use dioxus_core::prelude::*;
|
|||
|
||||
#[async_std::main]
|
||||
async fn main() {
|
||||
static App: FC<()> = |(cx, props)| Some(LazyNodes::new(|f| f.text(format_args!("hello"))));
|
||||
static App: FC<()> = |(cx, props)| cx.render(LazyNodes::new(|f| f.text(format_args!("hello"))));
|
||||
|
||||
let mut dom = VirtualDom::new(App);
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ use crate::{
|
|||
/// };
|
||||
/// ```
|
||||
///
|
||||
pub type Component<'a, T> = (Context<'a>, &'a T);
|
||||
pub type Scope<'a, T> = (Context<'a>, &'a T);
|
||||
|
||||
/// Create inline fragments using Component syntax.
|
||||
///
|
||||
|
@ -66,8 +66,8 @@ pub type Component<'a, T> = (Context<'a>, &'a T);
|
|||
/// You want to use this free-function when your fragment needs a key and simply returning multiple nodes from rsx! won't cut it.
|
||||
///
|
||||
#[allow(non_upper_case_globals, non_snake_case)]
|
||||
pub fn Fragment((cx, _): Component<()>) -> Element {
|
||||
Some(LazyNodes::new(|f| f.fragment_from_iter(cx.children())))
|
||||
pub fn Fragment((cx, _): Scope<()>) -> Element {
|
||||
cx.render(LazyNodes::new(move |f| f.fragment_from_iter(cx.children())))
|
||||
}
|
||||
|
||||
/// Every "Props" used for a component must implement the `Properties` trait. This trait gives some hints to Dioxus
|
||||
|
|
|
@ -32,7 +32,7 @@ use std::{any::TypeId, ops::Deref, rc::Rc};
|
|||
/// }
|
||||
/// ```
|
||||
pub struct Context<'src> {
|
||||
pub scope: &'src Scope,
|
||||
pub scope: &'src ScopeInner,
|
||||
}
|
||||
|
||||
impl<'src> Copy for Context<'src> {}
|
||||
|
@ -45,7 +45,7 @@ impl<'src> Clone for Context<'src> {
|
|||
// We currently deref to props, but it might make more sense to deref to Scope?
|
||||
// This allows for code that takes cx.xyz instead of cx.props.xyz
|
||||
impl<'a> Deref for Context<'a> {
|
||||
type Target = &'a Scope;
|
||||
type Target = &'a ScopeInner;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.scope
|
||||
}
|
||||
|
@ -137,7 +137,10 @@ impl<'src> Context<'src> {
|
|||
/// cx.render(lazy_tree)
|
||||
/// }
|
||||
///```
|
||||
pub fn render(self, lazy_nodes: LazyNodes<'src>) -> Option<VNode<'src>> {
|
||||
pub fn render<F: FnOnce(NodeFactory<'src>) -> VNode<'src>>(
|
||||
self,
|
||||
lazy_nodes: LazyNodes<'src, F>,
|
||||
) -> Option<VNode<'src>> {
|
||||
let bump = &self.scope.frames.wip_frame().bump;
|
||||
Some(lazy_nodes.into_vnode(NodeFactory { bump }))
|
||||
}
|
||||
|
|
|
@ -342,7 +342,7 @@ impl<'bump> DiffMachine<'bump> {
|
|||
let parent_scope = self.vdom.get_scope(parent_idx).unwrap();
|
||||
|
||||
let new_idx = self.vdom.insert_scope_with_key(|new_idx| {
|
||||
Scope::new(
|
||||
ScopeInner::new(
|
||||
caller,
|
||||
new_idx,
|
||||
Some(parent_idx),
|
||||
|
@ -1161,7 +1161,7 @@ impl<'bump> DiffMachine<'bump> {
|
|||
}
|
||||
|
||||
/// Adds a listener closure to a scope during diff.
|
||||
fn attach_listener_to_scope<'a>(&mut self, listener: &'a Listener<'a>, scope: &Scope) {
|
||||
fn attach_listener_to_scope<'a>(&mut self, listener: &'a Listener<'a>, scope: &ScopeInner) {
|
||||
let mut queue = scope.listeners.borrow_mut();
|
||||
let long_listener: &'a Listener<'static> = unsafe { std::mem::transmute(listener) };
|
||||
queue.push(long_listener as *const _)
|
||||
|
|
|
@ -135,32 +135,35 @@ where
|
|||
None => {
|
||||
let value = hook.value.clone();
|
||||
|
||||
Some(LazyNodes::new(|f| {
|
||||
let bump = f.bump();
|
||||
let id = hook.handle.our_id;
|
||||
|
||||
use bumpalo::boxed::Box as BumpBox;
|
||||
todo!()
|
||||
// Some(LazyNodes::new(move |f| {
|
||||
// let bump = f.bump();
|
||||
|
||||
let f: &mut dyn FnMut(SuspendedContext<'src>) -> Element<'src> =
|
||||
bump.alloc(move |sus| {
|
||||
let val = value.borrow();
|
||||
// use bumpalo::boxed::Box as BumpBox;
|
||||
|
||||
let out = val
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.downcast_ref::<Out>()
|
||||
.unwrap();
|
||||
// let f: &mut dyn FnMut(SuspendedContext<'src>) -> Element<'src> =
|
||||
// bump.alloc(move |sus| {
|
||||
// let val = value.borrow();
|
||||
|
||||
user_callback(sus, out)
|
||||
});
|
||||
let callback = unsafe { BumpBox::from_raw(f) };
|
||||
// let out = val
|
||||
// .as_ref()
|
||||
// .unwrap()
|
||||
// .as_ref()
|
||||
// .downcast_ref::<Out>()
|
||||
// .unwrap();
|
||||
|
||||
VNode::Suspended(bump.alloc(VSuspended {
|
||||
dom_id: empty_cell(),
|
||||
task_id: hook.handle.our_id,
|
||||
callback: RefCell::new(Some(callback)),
|
||||
}))
|
||||
}))
|
||||
// user_callback(sus, out)
|
||||
// });
|
||||
// let callback = unsafe { BumpBox::from_raw(f) };
|
||||
|
||||
// VNode::Suspended(bump.alloc(VSuspended {
|
||||
// dom_id: empty_cell(),
|
||||
// task_id: id,
|
||||
// callback: RefCell::new(Some(callback)),
|
||||
// }))
|
||||
// }))
|
||||
}
|
||||
},
|
||||
|_| {},
|
||||
|
@ -177,10 +180,10 @@ pub struct SuspendedContext<'a> {
|
|||
}
|
||||
|
||||
impl<'src> SuspendedContext<'src> {
|
||||
pub fn render(
|
||||
// pub fn render<F: FnOnce(NodeFactory<'src>) -> VNode<'src>>(
|
||||
// pub fn render(
|
||||
pub fn render<F: FnOnce(NodeFactory<'src>) -> VNode<'src>>(
|
||||
self,
|
||||
lazy_nodes: LazyNodes<'src>,
|
||||
lazy_nodes: LazyNodes<'src, F>,
|
||||
) -> Element<'src> {
|
||||
let bump = &self.inner.scope.frames.wip_frame().bump;
|
||||
todo!("suspense")
|
||||
|
|
113
packages/core/src/lazynodes.rs
Normal file
113
packages/core/src/lazynodes.rs
Normal file
|
@ -0,0 +1,113 @@
|
|||
use std::marker::PhantomData;
|
||||
|
||||
/*
|
||||
Remember: calls to rsx! are lazy - they are not evaluated immediately.
|
||||
|
||||
They also using dynamic dispatch, so we can return multiple rsx!'s from match statements and such.
|
||||
|
||||
If we allocated every rsx! call on the heap, it would be quite wasteful. Rsx! calls are FnOnce, so they can be stored in a stack.
|
||||
|
||||
Solutions like stackdst are useful, but they only support 'static closures.
|
||||
|
||||
All our closures are bound by the bump lifetime, so stack-dst will not work for us
|
||||
|
||||
Our solution is to try and manually allocate the closure onto the stack.
|
||||
If it fails, then we default to Box.
|
||||
|
||||
*/
|
||||
use crate::innerlude::{IntoVNode, NodeFactory, VNode};
|
||||
|
||||
/// A concrete type provider for closures that build VNode structures.
|
||||
///
|
||||
/// This struct wraps lazy structs that build VNode trees Normally, we cannot perform a blanket implementation over
|
||||
/// closures, but if we wrap the closure in a concrete type, we can maintain separate implementations of IntoVNode.
|
||||
///
|
||||
///
|
||||
/// ```rust
|
||||
/// LazyNodes::new(|f| f.element("div", [], [], [] None))
|
||||
/// ```
|
||||
pub struct LazyNodes<'a, F: FnOnce(NodeFactory<'a>) -> VNode<'a>> {
|
||||
inner: Box<F>,
|
||||
_p: PhantomData<&'a ()>,
|
||||
// inner: StackNodeStorage<'a>,
|
||||
// inner: StackNodeStorage<'a>,
|
||||
}
|
||||
|
||||
type StackHeapSize = [usize; 12];
|
||||
|
||||
enum StackNodeStorage<'a> {
|
||||
Stack {
|
||||
next_ofs: usize,
|
||||
buf: StackHeapSize,
|
||||
width: usize,
|
||||
},
|
||||
Heap(Box<dyn FnOnce(NodeFactory<'a>) -> VNode<'a>>),
|
||||
}
|
||||
|
||||
impl<'a, F: FnOnce(NodeFactory<'a>) -> VNode<'a>> LazyNodes<'a, F> {
|
||||
pub fn new(f: F) -> Self {
|
||||
// let width = std::mem?::size_of::<F>();
|
||||
// let b: Box<dyn FnOnce(NodeFactory<'a>) -> VNode<'a>> = Box::new(f);
|
||||
|
||||
todo!()
|
||||
// Self { inner: b }
|
||||
// todo!()
|
||||
|
||||
// if width > std::mem::size_of::<StackHeapSize>() {
|
||||
// let g: Box<dyn for<'b> FnOnce(NodeFactory<'b>) -> VNode<'b> + 'g> = Box::new(f);
|
||||
// LazyNodes {
|
||||
// inner: StackNodeStorage::Heap(g),
|
||||
// }
|
||||
// } else {
|
||||
// let mut buf = [0; 12];
|
||||
// let mut next_ofs = 0;
|
||||
// next_ofs += 1;
|
||||
// LazyNodes {
|
||||
// inner: StackNodeStorage::Stack {
|
||||
// next_ofs,
|
||||
// buf,
|
||||
// width,
|
||||
// },
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
// Our blanket impl
|
||||
impl<'a, F> IntoIterator for LazyNodes<'a, F>
|
||||
where
|
||||
F: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
{
|
||||
type Item = Self;
|
||||
type IntoIter = std::iter::Once<Self::Item>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
std::iter::once(self)
|
||||
}
|
||||
}
|
||||
|
||||
// Our blanket impl
|
||||
impl<'a, F: FnOnce(NodeFactory<'a>) -> VNode<'a>> IntoVNode<'a> for LazyNodes<'a, F> {
|
||||
fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
|
||||
todo!()
|
||||
// match self.inner {
|
||||
// StackNodeStorage::Stack {
|
||||
// buf,
|
||||
// next_ofs,
|
||||
// width,
|
||||
// } => {
|
||||
// // get the start of the allocation
|
||||
// let r = &buf[0];
|
||||
|
||||
// // recast the allocation as dyn FnOnce
|
||||
|
||||
// // pretend the FnOnce is box
|
||||
// let g: Box<dyn FnOnce(NodeFactory<'a>) -> VNode<'a>> = todo!();
|
||||
// // Box::from_raw(r as *const usize as *mut dyn FnOnce(NodeFactory<'a>));
|
||||
|
||||
// // use Box's ability to act as FnOnce
|
||||
// g(cx)
|
||||
// }
|
||||
// StackNodeStorage::Heap(b) => b(cx),
|
||||
// }
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@ pub mod events;
|
|||
pub mod heuristics;
|
||||
pub mod hooklist;
|
||||
pub mod hooks;
|
||||
pub mod lazynodes;
|
||||
pub mod mutations;
|
||||
pub mod nodes;
|
||||
pub mod resources;
|
||||
|
@ -45,6 +46,7 @@ pub(crate) mod innerlude {
|
|||
pub use crate::heuristics::*;
|
||||
pub(crate) use crate::hooklist::*;
|
||||
pub use crate::hooks::*;
|
||||
pub use crate::lazynodes::LazyNodes;
|
||||
pub use crate::mutations::*;
|
||||
pub use crate::nodes::*;
|
||||
pub(crate) use crate::resources::*;
|
||||
|
@ -55,10 +57,9 @@ pub(crate) mod innerlude {
|
|||
pub use crate::threadsafe::*;
|
||||
pub use crate::util::*;
|
||||
pub use crate::virtual_dom::*;
|
||||
|
||||
// pub type Element<'a> = Option<VNode<'a>>;
|
||||
pub type Element<'a> = Option<LazyNodes<'a>>;
|
||||
pub type FC<P> = for<'a> fn(Component<'a, P>) -> Element<'a>;
|
||||
pub type Element<'a> = Option<VNode<'a>>;
|
||||
pub type FC<P> = for<'a> fn(Scope<'a, P>) -> Element<'a>;
|
||||
}
|
||||
|
||||
pub use crate::innerlude::{
|
||||
|
@ -68,7 +69,7 @@ pub use crate::innerlude::{
|
|||
};
|
||||
|
||||
pub mod prelude {
|
||||
pub use crate::component::{fc_to_builder, Component, Fragment, Properties};
|
||||
pub use crate::component::{fc_to_builder, Fragment, Properties, Scope};
|
||||
pub use crate::context::Context;
|
||||
pub use crate::hooks::*;
|
||||
pub use crate::innerlude::{DioxusElement, Element, LazyNodes, Mutations, NodeFactory, FC};
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
//! cheap and *very* fast to construct - building a full tree should be quick.
|
||||
|
||||
use crate::innerlude::{
|
||||
empty_cell, Context, Element, ElementId, Properties, Scope, ScopeId, SuspendedContext, FC,
|
||||
empty_cell, Context, Element, ElementId, LazyNodes, Properties, ScopeId, ScopeInner,
|
||||
SuspendedContext, FC,
|
||||
};
|
||||
use bumpalo::{boxed::Box as BumpBox, Bump};
|
||||
use std::{
|
||||
|
@ -13,10 +14,6 @@ use std::{
|
|||
marker::PhantomData,
|
||||
};
|
||||
|
||||
use stack_dst::Value as StackDST;
|
||||
|
||||
pub type LazyNodeFactory<'a> = StackDST<dyn FnOnce(NodeFactory<'a>) -> VNode<'a>>;
|
||||
|
||||
/// A composable "VirtualNode" to declare a User Interface in the Dioxus VirtualDOM.
|
||||
///
|
||||
/// VNodes are designed to be lightweight and used with with a bump allocator. To create a VNode, you can use either of:
|
||||
|
@ -291,7 +288,7 @@ pub struct VComponent<'src> {
|
|||
// Function pointer to the FC that was used to generate this component
|
||||
pub user_fc: *const (),
|
||||
|
||||
pub(crate) caller: &'src dyn for<'b> Fn(&'b Scope) -> Element<'b>,
|
||||
pub(crate) caller: &'src dyn for<'b> Fn(&'b ScopeInner) -> Element<'b>,
|
||||
|
||||
pub(crate) children: &'src [VNode<'src>],
|
||||
|
||||
|
@ -332,11 +329,11 @@ impl<'a> NodeFactory<'a> {
|
|||
self.bump
|
||||
}
|
||||
|
||||
pub fn render_directly<F>(&self, lazy_nodes: LazyNodes<'a>) -> Option<VNode<'a>>
|
||||
// pub fn render_directly<F>(&self, lazy_nodes: LazyNodes<'a, F>) -> Element<'a>
|
||||
// where
|
||||
// F: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
pub fn render_directly<F>(&self, lazy_nodes: LazyNodes<'a, F>) -> Element<'a>
|
||||
where
|
||||
F: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
{
|
||||
// pub fn render_directly<F>(&self, lazy_nodes: LazyNodes<'a>) -> Option<VNode<'a>> {
|
||||
Some(lazy_nodes.into_vnode(NodeFactory { bump: self.bump }))
|
||||
}
|
||||
|
||||
|
@ -531,8 +528,8 @@ impl<'a> NodeFactory<'a> {
|
|||
|
||||
let key = key.map(|f| self.raw_text(f).0);
|
||||
|
||||
let caller: &'a mut dyn for<'b> Fn(&'b Scope) -> Element<'b> =
|
||||
bump.alloc(move |scope: &Scope| -> Element {
|
||||
let caller: &'a mut dyn for<'b> Fn(&'b ScopeInner) -> Element<'b> =
|
||||
bump.alloc(move |scope: &ScopeInner| -> Element {
|
||||
log::debug!("calling component renderr {:?}", scope.our_arena_idx);
|
||||
let props: &'_ P = unsafe { &*(raw_props as *const P) };
|
||||
let res: Element = component((Context { scope }, props));
|
||||
|
@ -687,60 +684,6 @@ impl<'a> IntoVNode<'a> for VNode<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// A concrete type provider for closures that build VNode structures.
|
||||
///
|
||||
/// This struct wraps lazy structs that build VNode trees Normally, we cannot perform a blanket implementation over
|
||||
/// closures, but if we wrap the closure in a concrete type, we can maintain separate implementations of IntoVNode.
|
||||
///
|
||||
///
|
||||
/// ```rust
|
||||
/// LazyNodes::new(|f| f.element("div", [], [], [] None))
|
||||
/// ```
|
||||
pub struct LazyNodes<'a> {
|
||||
inner: LazyNodeFactory<'a>,
|
||||
}
|
||||
// where
|
||||
// G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
|
||||
impl<'a> LazyNodes<'a>
|
||||
// where
|
||||
// G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
{
|
||||
pub fn new(f: impl FnOnce(NodeFactory<'a>) -> VNode<'a>) -> Self {
|
||||
todo!()
|
||||
// pub fn new<G: FnOnce(NodeFactory<'a>) -> VNode<'a>>(f: G) -> Self {
|
||||
// let inner = LazyNodeFactory::new(f);
|
||||
// Self { inner: f }
|
||||
}
|
||||
}
|
||||
|
||||
// Our blanket impl
|
||||
impl<'a> IntoVNode<'a> for LazyNodes<'a>
|
||||
// where
|
||||
// G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
{
|
||||
fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
|
||||
// let f = self.inner;
|
||||
todo!("manually drop here")
|
||||
// (self.inner)(cx)
|
||||
}
|
||||
}
|
||||
|
||||
// Our blanket impl
|
||||
impl<'a> IntoIterator for LazyNodes<'a>
|
||||
// where
|
||||
// G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
// impl<'a, G> IntoIterator for LazyNodes<'a, G>
|
||||
// where
|
||||
// G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
{
|
||||
type Item = Self;
|
||||
type IntoIter = std::iter::Once<Self::Item>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
std::iter::once(self)
|
||||
}
|
||||
}
|
||||
|
||||
// Conveniently, we also support "null" (nothing) passed in
|
||||
impl IntoVNode<'_> for () {
|
||||
fn into_vnode(self, cx: NodeFactory) -> VNode {
|
||||
|
@ -764,7 +707,7 @@ impl<'a> IntoVNode<'a> for Option<VNode<'a>> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoVNode<'a> for Option<LazyNodes<'a>> {
|
||||
impl<'a, F: FnOnce(NodeFactory<'a>) -> VNode<'a>> IntoVNode<'a> for Option<LazyNodes<'a, F>> {
|
||||
fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
|
||||
match self {
|
||||
Some(n) => n.into_vnode(cx),
|
||||
|
|
|
@ -15,7 +15,7 @@ pub(crate) struct ResourcePool {
|
|||
|
||||
Wrapped in Rc so the "get_shared_context" closure can walk the tree (immutably!)
|
||||
*/
|
||||
pub components: Rc<UnsafeCell<Slab<Scope>>>,
|
||||
pub components: Rc<UnsafeCell<Slab<ScopeInner>>>,
|
||||
|
||||
/*
|
||||
Yes, a slab of "nil". We use this for properly ordering ElementIDs - all we care about is the allocation strategy
|
||||
|
@ -32,18 +32,18 @@ pub(crate) struct ResourcePool {
|
|||
|
||||
impl ResourcePool {
|
||||
/// this is unsafe because the caller needs to track which other scopes it's already using
|
||||
pub fn get_scope(&self, idx: ScopeId) -> Option<&Scope> {
|
||||
pub fn get_scope(&self, idx: ScopeId) -> Option<&ScopeInner> {
|
||||
let inner = unsafe { &*self.components.get() };
|
||||
inner.get(idx.0)
|
||||
}
|
||||
|
||||
/// this is unsafe because the caller needs to track which other scopes it's already using
|
||||
pub fn get_scope_mut(&self, idx: ScopeId) -> Option<&mut Scope> {
|
||||
pub fn get_scope_mut(&self, idx: ScopeId) -> Option<&mut ScopeInner> {
|
||||
let inner = unsafe { &mut *self.components.get() };
|
||||
inner.get_mut(idx.0)
|
||||
}
|
||||
|
||||
pub fn try_remove(&self, id: ScopeId) -> Option<Scope> {
|
||||
pub fn try_remove(&self, id: ScopeId) -> Option<ScopeInner> {
|
||||
let inner = unsafe { &mut *self.components.get() };
|
||||
Some(inner.remove(id.0))
|
||||
// .try_remove(id.0)
|
||||
|
@ -67,7 +67,7 @@ impl ResourcePool {
|
|||
els.remove(id.0);
|
||||
}
|
||||
|
||||
pub fn insert_scope_with_key(&self, f: impl FnOnce(ScopeId) -> Scope) -> ScopeId {
|
||||
pub fn insert_scope_with_key(&self, f: impl FnOnce(ScopeId) -> ScopeInner) -> ScopeId {
|
||||
let g = unsafe { &mut *self.components.get() };
|
||||
let entry = g.vacant_entry();
|
||||
let id = ScopeId(entry.key());
|
||||
|
|
|
@ -214,7 +214,7 @@ impl Scheduler {
|
|||
let components = components.clone();
|
||||
Rc::new(move |id, ty| {
|
||||
let components = unsafe { &*components.get() };
|
||||
let mut search: Option<&Scope> = components.get(id.0);
|
||||
let mut search: Option<&ScopeInner> = components.get(id.0);
|
||||
while let Some(inner) = search.take() {
|
||||
if let Some(shared) = inner.shared_contexts.borrow().get(&ty) {
|
||||
return Some(shared.clone());
|
||||
|
|
|
@ -18,7 +18,7 @@ use std::{
|
|||
///
|
||||
/// We expose the `Scope` type so downstream users can traverse the Dioxus VirtualDOM for whatever
|
||||
/// use case they might have.
|
||||
pub struct Scope {
|
||||
pub struct ScopeInner {
|
||||
// Book-keeping about our spot in the arena
|
||||
pub(crate) parent_idx: Option<ScopeId>,
|
||||
pub(crate) our_arena_idx: ScopeId,
|
||||
|
@ -28,7 +28,7 @@ pub struct Scope {
|
|||
|
||||
// Nodes
|
||||
pub(crate) frames: ActiveFrame,
|
||||
pub(crate) caller: *const dyn for<'b> Fn(&'b Scope) -> Element<'b>,
|
||||
pub(crate) caller: *const dyn for<'b> Fn(&'b ScopeInner) -> Element<'b>,
|
||||
pub(crate) child_nodes: ScopeChildren<'static>,
|
||||
|
||||
/*
|
||||
|
@ -55,7 +55,7 @@ pub struct Scope {
|
|||
}
|
||||
|
||||
/// Public interface for Scopes.
|
||||
impl Scope {
|
||||
impl ScopeInner {
|
||||
/// Get the root VNode for this Scope.
|
||||
///
|
||||
/// This VNode is the "entrypoint" VNode. If the component renders multiple nodes, then this VNode will be a fragment.
|
||||
|
@ -167,7 +167,7 @@ impl Scope {
|
|||
pub type FiberTask = Pin<Box<dyn Future<Output = ScopeId>>>;
|
||||
|
||||
/// Private interface for Scopes.
|
||||
impl Scope {
|
||||
impl ScopeInner {
|
||||
// we are being created in the scope of an existing component (where the creator_node lifetime comes into play)
|
||||
// we are going to break this lifetime by force in order to save it on ourselves.
|
||||
// To make sure that the lifetime isn't truly broken, we receive a Weak RC so we can't keep it around after the parent dies.
|
||||
|
@ -176,7 +176,7 @@ impl Scope {
|
|||
// Scopes cannot be made anywhere else except for this file
|
||||
// Therefore, their lifetimes are connected exclusively to the virtual dom
|
||||
pub(crate) fn new(
|
||||
caller: &dyn for<'b> Fn(&'b Scope) -> Element<'b>,
|
||||
caller: &dyn for<'b> Fn(&'b ScopeInner) -> Element<'b>,
|
||||
our_arena_idx: ScopeId,
|
||||
parent_idx: Option<ScopeId>,
|
||||
height: u32,
|
||||
|
@ -217,7 +217,7 @@ impl Scope {
|
|||
|
||||
pub(crate) fn update_scope_dependencies<'creator_node>(
|
||||
&mut self,
|
||||
caller: &'creator_node dyn for<'b> Fn(&'b Scope) -> Element<'b>,
|
||||
caller: &'creator_node dyn for<'b> Fn(&'b ScopeInner) -> Element<'b>,
|
||||
child_nodes: ScopeChildren,
|
||||
) {
|
||||
log::debug!("Updating scope dependencies {:?}", self.our_arena_idx);
|
||||
|
@ -350,7 +350,7 @@ impl Scope {
|
|||
log::debug!("Borrowed stuff is successfully cleared");
|
||||
|
||||
// Cast the caller ptr from static to one with our own reference
|
||||
let render: &dyn for<'b> Fn(&'b Scope) -> 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.
|
||||
//
|
||||
|
@ -376,7 +376,7 @@ impl Scope {
|
|||
pub(crate) struct ScopeRenderer<'a> {
|
||||
pub skip_components: bool,
|
||||
pub show_fragments: bool,
|
||||
pub _scope: &'a Scope,
|
||||
pub _scope: &'a ScopeInner,
|
||||
pub _pre_render: bool,
|
||||
pub _newline: bool,
|
||||
pub _indent: bool,
|
||||
|
|
|
@ -143,7 +143,8 @@ impl VirtualDom {
|
|||
|
||||
let _p = root_props.clone();
|
||||
// Safety: this callback is only valid for the lifetime of the root props
|
||||
let root_caller: Rc<dyn Fn(&Scope) -> Element> = Rc::new(move |scope: &Scope| unsafe {
|
||||
let root_caller: Rc<dyn Fn(&ScopeInner) -> Element> =
|
||||
Rc::new(move |scope: &ScopeInner| unsafe {
|
||||
let props = _p.downcast_ref::<P>().unwrap();
|
||||
std::mem::transmute(root((Context { scope }, props)))
|
||||
});
|
||||
|
@ -151,7 +152,7 @@ impl VirtualDom {
|
|||
let scheduler = Scheduler::new(sender, receiver);
|
||||
|
||||
let base_scope = scheduler.pool.insert_scope_with_key(|myidx| {
|
||||
Scope::new(
|
||||
ScopeInner::new(
|
||||
root_caller.as_ref(),
|
||||
myidx,
|
||||
None,
|
||||
|
@ -175,12 +176,12 @@ impl VirtualDom {
|
|||
///
|
||||
/// This is useful for traversing the tree from the root for heuristics or alternsative renderers that use Dioxus
|
||||
/// directly.
|
||||
pub fn base_scope(&self) -> &Scope {
|
||||
pub fn base_scope(&self) -> &ScopeInner {
|
||||
self.scheduler.pool.get_scope(self.base_scope).unwrap()
|
||||
}
|
||||
|
||||
/// Get the [`Scope`] for a component given its [`ScopeId`]
|
||||
pub fn get_scope(&self, id: ScopeId) -> Option<&Scope> {
|
||||
pub fn get_scope(&self, id: ScopeId) -> Option<&ScopeInner> {
|
||||
self.scheduler.pool.get_scope(id)
|
||||
}
|
||||
|
||||
|
@ -219,8 +220,8 @@ impl VirtualDom {
|
|||
|
||||
let root = *self.root_fc.downcast_ref::<FC<P>>().unwrap();
|
||||
|
||||
let root_caller: Box<dyn Fn(&Scope) -> Element> =
|
||||
Box::new(move |scope: &Scope| unsafe {
|
||||
let root_caller: Box<dyn Fn(&ScopeInner) -> Element> =
|
||||
Box::new(move |scope: &ScopeInner| unsafe {
|
||||
let props: &'_ P = &*(props_ptr as *const P);
|
||||
std::mem::transmute(root((Context { scope }, props)))
|
||||
});
|
||||
|
@ -410,4 +411,4 @@ impl std::fmt::Display for VirtualDom {
|
|||
}
|
||||
|
||||
// we never actually use the contents of this root caller
|
||||
struct RootCaller(Rc<dyn for<'b> Fn(&'b Scope) -> Element<'b> + 'static>);
|
||||
struct RootCaller(Rc<dyn for<'b> Fn(&'b ScopeInner) -> Element<'b> + 'static>);
|
||||
|
|
|
@ -10,7 +10,7 @@ fn test_borrowed_state() {
|
|||
let _ = VirtualDom::new(Parent);
|
||||
}
|
||||
|
||||
fn Parent((cx, _): Component<()>) -> Element {
|
||||
fn Parent((cx, _): Scope<()>) -> Element {
|
||||
let value = cx.use_hook(|_| String::new(), |f| &*f, |_| {});
|
||||
|
||||
rsx! {
|
||||
|
@ -28,7 +28,7 @@ struct ChildProps<'a> {
|
|||
name: &'a str,
|
||||
}
|
||||
|
||||
fn Child<'a>((cx, props): Component<'a, ChildProps>) -> Element<'a> {
|
||||
fn Child<'a>((cx, props): Scope<'a, ChildProps>) -> Element<'a> {
|
||||
rsx! {
|
||||
div {
|
||||
h1 { "it's nested" }
|
||||
|
@ -42,7 +42,7 @@ struct Grandchild<'a> {
|
|||
name: &'a str,
|
||||
}
|
||||
|
||||
fn Child2<'a>((cx, props): Component<'a, Grandchild>) -> Element<'a> {
|
||||
fn Child2<'a>((cx, props): Scope<'a, Grandchild>) -> Element<'a> {
|
||||
rsx! {
|
||||
div { "Hello {props.name}!" }
|
||||
}
|
||||
|
|
|
@ -92,7 +92,7 @@ fn child_components() {
|
|||
#[test]
|
||||
fn suspended_works() {
|
||||
static App: FC<()> = |(cx, props)| {
|
||||
let title = use_suspense(cx, || async { "bob" }, |cx, f| rsx! { "{f}"});
|
||||
let title = use_suspense(cx, || async { "bob" }, move |cx, f| rsx! { "{f}"});
|
||||
rsx!("hello" { title })
|
||||
};
|
||||
|
||||
|
|
|
@ -136,7 +136,7 @@ pub struct TodoEntryProps {
|
|||
id: u32,
|
||||
}
|
||||
|
||||
pub fn TodoEntry((cx, props): Component<TodoEntryProps>) -> Element {
|
||||
pub fn TodoEntry((cx, props): Scope<TodoEntryProps>) -> Element {
|
||||
let todos = use_shared_state::<Todos>(cx)?;
|
||||
|
||||
let _todos = todos.read();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::cell::RefCell;
|
||||
|
||||
use dioxus::prelude::Component;
|
||||
use dioxus::prelude::Scope;
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::{Context, Element, LazyNodes, NodeFactory, Properties};
|
||||
use dioxus_core_macro::Props;
|
||||
|
@ -54,7 +54,7 @@ pub struct WebviewWindowProps<'a> {
|
|||
///
|
||||
///
|
||||
///
|
||||
pub fn WebviewWindow<'a>((cx, props): Component<'a, WebviewWindowProps>) -> Element<'a> {
|
||||
pub fn WebviewWindow<'a>((cx, props): Scope<'a, WebviewWindowProps>) -> Element<'a> {
|
||||
let dtcx = cx.consume_state::<RefCell<DesktopContext>>()?;
|
||||
|
||||
cx.use_hook(
|
||||
|
|
Loading…
Reference in a new issue