`children` should take `FnOnce(Scope) -> Fragment`, to ease need of cloning etc.

This commit is contained in:
Greg Johnston 2023-01-07 17:04:58 -05:00
parent 0956c48b1e
commit f2842cf14e
8 changed files with 28 additions and 28 deletions

View File

@ -1,10 +1,10 @@
use cfg_if::cfg_if;
use leptos_macro::component;
use std::rc::Rc;
use leptos_dom::{DynChild, Fragment, IntoView, Component};
use leptos_reactive::{provide_context, Scope, SuspenseContext};
use leptos_dom::{Component, DynChild, Fragment, IntoView};
#[cfg(not(any(feature = "csr", feature = "hydrate")))]
use leptos_dom::{HydrationCtx, HydrationKey};
use leptos_macro::component;
use leptos_reactive::{provide_context, Scope, SuspenseContext};
use std::rc::Rc;
/// If any [Resources](leptos_reactive::Resource) are read in the `children` of this
/// component, it will show the `fallback` while they are loading. Once all are resolved,
@ -58,7 +58,7 @@ pub fn Suspense<F, E>(
/// Returns a fallback UI that will be shown while `async` [Resources](leptos_reactive::Resource) are still loading.
fallback: F,
/// Children will be displayed once all `async` [Resources](leptos_reactive::Resource) have resolved.
children: Box<dyn Fn(Scope) -> Fragment>,
children: Box<dyn FnOnce(Scope) -> Fragment>,
) -> impl IntoView
where
F: Fn() -> E + 'static,
@ -88,8 +88,8 @@ where
} else {
// run the child; we'll probably throw this away, but it will register resource reads
let child = orig_child(cx).into_view(cx);
let initial = {
let initial = {
// no resources were read under this, so just return the child
if context.pending_resources.get() == 0 {
child.clone()
@ -97,10 +97,10 @@ where
// show the fallback, but also prepare to stream HTML
else {
let orig_child = Rc::clone(&orig_child);
cx.register_suspense(
context,
&id_before_suspense.to_string(),
&id_before_suspense.to_string(),
&current_id.to_string(),
{
let current_id = current_id.clone();
@ -117,17 +117,17 @@ where
}
}
);
// return the fallback for now, wrapped in fragment identifer
fallback().into_view(cx)
}
};
HydrationCtx::continue_from(current_id.clone());
initial
}
}
})
})
}
}

View File

@ -1,6 +1,6 @@
use leptos_dom::{Fragment, IntoView, View};
use leptos_macro::component;
use leptos_reactive::{ Scope, SignalSetter};
use leptos_reactive::{Scope, SignalSetter};
use std::{cell::RefCell, rc::Rc};
/// If any [Resource](leptos_reactive::Resource)s are read in the `children` of this
@ -66,7 +66,7 @@ pub fn Transition<F, E>(
#[prop(optional)]
set_pending: Option<SignalSetter<bool>>,
/// Will be displayed once all resources have resolved.
children: Box<dyn Fn(Scope) -> Fragment>
children: Box<dyn FnOnce(Scope) -> Fragment>,
) -> impl IntoView
where
F: Fn() -> E + 'static,
@ -98,6 +98,6 @@ where
}
frag
}))
.build()
.build(),
)
}
}

View File

@ -358,12 +358,12 @@ pub fn view(tokens: TokenStream) -> TokenStream {
/// ```
///
/// 5. You can access the children passed into the component with the `children` property, which takes
/// an argument of the form `Box<dyn Fn(Scope) -> Fragment>`.
/// an argument of the form `Box<dyn FnOnce(Scope) -> Fragment>`.
///
/// ```
/// # use leptos::*;
/// #[component]
/// fn ComponentWithChildren(cx: Scope, children: Box<dyn Fn(Scope) -> Fragment>) -> impl IntoView {
/// fn ComponentWithChildren(cx: Scope, children: Box<dyn FnOnce(Scope) -> Fragment>) -> impl IntoView {
/// view! {
/// cx,
/// <ul>

View File

@ -36,7 +36,7 @@ pub fn Form<A>(
#[prop(optional)]
on_response: Option<Rc<dyn Fn(&web_sys::Response)>>,
/// Component children; should include the HTML of the form elements.
children: Box<dyn Fn(Scope) -> Fragment>,
children: Box<dyn FnOnce(Scope) -> Fragment>,
) -> impl IntoView
where
A: ToHref + 'static,
@ -134,7 +134,7 @@ pub fn ActionForm<I, O>(
/// manually using [leptos_server::Action::using_server_fn].
action: Action<I, Result<O, ServerFnError>>,
/// Component children; should include the HTML of the form elements.
children: Box<dyn Fn(Scope) -> Fragment>,
children: Box<dyn FnOnce(Scope) -> Fragment>,
) -> impl IntoView
where
I: Clone + ServerFn + 'static,
@ -208,7 +208,7 @@ pub fn MultiActionForm<I, O>(
/// manually using [leptos_server::Action::using_server_fn].
action: MultiAction<I, Result<O, ServerFnError>>,
/// Component children; should include the HTML of the form elements.
children: Box<dyn Fn(Scope) -> Fragment>,
children: Box<dyn FnOnce(Scope) -> Fragment>,
) -> impl IntoView
where
I: Clone + ServerFn + 'static,

View File

@ -58,7 +58,7 @@ pub fn A<H>(
#[prop(optional, into)]
class: Option<MaybeSignal<String>>,
/// The nodes or elements to be shown inside the link.
children: Box<dyn Fn(Scope) -> Fragment>,
children: Box<dyn FnOnce(Scope) -> Fragment>,
) -> impl IntoView
where
H: ToHref + 'static,

View File

@ -26,7 +26,7 @@ pub fn Route<E, F, P>(
view: F,
/// `children` may be empty or include nested routes.
#[prop(optional)]
children: Option<Box<dyn Fn(Scope) -> Fragment>>,
children: Option<Box<dyn FnOnce(Scope) -> Fragment>>,
) -> impl IntoView
where
E: IntoView,

View File

@ -32,7 +32,7 @@ pub fn Router(
/// The `<Router/>` should usually wrap your whole page. It can contain
/// any elements, and should include a [Routes](crate::Routes) component somewhere
/// to define and display [Route](crate::Route)s.
children: Box<dyn Fn(Scope) -> Fragment>,
children: Box<dyn FnOnce(Scope) -> Fragment>,
) -> impl IntoView {
// create a new RouterContext and provide it to every component beneath the router
let router = RouterContext::new(cx, base, fallback);
@ -104,10 +104,10 @@ impl RouterContext {
value: base_path.to_string(),
replace: true,
scroll: false,
state: State(None)
state: State(None),
});
}
}
}
// the current URL
let (reference, set_reference) = create_signal(cx, source.with(|s| s.value.clone()));

View File

@ -22,7 +22,7 @@ use crate::{
pub fn Routes(
cx: Scope,
#[prop(optional)] base: Option<String>,
children: Box<dyn Fn(Scope) -> Fragment>,
children: Box<dyn FnOnce(Scope) -> Fragment>,
) -> impl IntoView {
let router = use_context::<RouterContext>(cx).unwrap_or_else(|| {
log::warn!("<Routes/> component should be nested within a <Router/>.");