diff --git a/leptos/src/lib.rs b/leptos/src/lib.rs index ac4a6b8ac2..02d98908b7 100644 --- a/leptos/src/lib.rs +++ b/leptos/src/lib.rs @@ -192,9 +192,11 @@ mod error_boundary; pub use error_boundary::*; mod animated_show; mod for_loop; +mod provider; mod show; pub use animated_show::*; pub use for_loop::*; +pub use provider::*; #[cfg(feature = "experimental-islands")] pub use serde; #[cfg(feature = "experimental-islands")] diff --git a/leptos/src/provider.rs b/leptos/src/provider.rs new file mode 100644 index 0000000000..39dff0756f --- /dev/null +++ b/leptos/src/provider.rs @@ -0,0 +1,40 @@ +use leptos::*; + +#[component] +/// Uses the context API to [`provide_context`] to its children and descendants, +/// without overwriting any contexts of the same type in its own reactive scope. +/// +/// This prevents issues related to “context shadowing.” +/// +/// ```rust +/// # use leptos::*; +/// #[component] +/// pub fn App() -> impl IntoView { +/// // each Provider will only provide the value to its children +/// view! { +/// +/// // correctly gets 1 from context +/// {use_context::().unwrap_or(0)} +/// +/// +/// // correctly gets 2 from context +/// {use_context::().unwrap_or(0)} +/// +/// // does not find any u8 in context +/// {use_context::().unwrap_or(0)} +/// } +/// } +/// ``` +pub fn Provider( + /// The value to be provided via context. + value: T, + children: Children, +) -> impl IntoView +where + T: Clone + 'static, +{ + run_as_child(move || { + provide_context(value); + children() + }) +} diff --git a/leptos_reactive/src/context.rs b/leptos_reactive/src/context.rs index 266df64b7a..5037fc2539 100644 --- a/leptos_reactive/src/context.rs +++ b/leptos_reactive/src/context.rs @@ -84,7 +84,29 @@ use std::any::{Any, TypeId}; /// that was provided in ``, meaning that the second `` receives the context /// from its sibling instead. /// -/// This can be solved by introducing some additional reactivity. In this case, it’s simplest +/// ### Solution +/// +/// If you are using the full Leptos framework, you can use the [`Provider`](leptos::Provider) +/// component to solve this issue. +/// +/// ```rust +/// # use leptos::*; +/// #[component] +/// fn Child() -> impl IntoView { +/// let context = expect_context::<&'static str>(); +/// // creates a new reactive node, which means the context will +/// // only be provided to its children, not modified in the parent +/// view! { +/// +///
{format!("child (context: {context})")}
+///
+/// } +/// } +/// ``` +/// +/// ### Alternate Solution +/// +/// This can also be solved by introducing some additional reactivity. In this case, it’s simplest /// to simply make the body of `` a function, which means it will be wrapped in a /// new reactive node when rendered: /// ```rust