mirror of
https://github.com/leptos-rs/leptos.git
synced 2025-12-29 00:12:40 -05:00
Compare commits
1 Commits
1952
...
context-pr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e7cfe788b2 |
@@ -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")]
|
||||
|
||||
40
leptos/src/provider.rs
Normal file
40
leptos/src/provider.rs
Normal file
@@ -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! {
|
||||
/// <Provider value=1u8>
|
||||
/// // correctly gets 1 from context
|
||||
/// {use_context::<u8>().unwrap_or(0)}
|
||||
/// </Provider>
|
||||
/// <Provider value=2u8>
|
||||
/// // correctly gets 2 from context
|
||||
/// {use_context::<u8>().unwrap_or(0)}
|
||||
/// </Provider>
|
||||
/// // does not find any u8 in context
|
||||
/// {use_context::<u8>().unwrap_or(0)}
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub fn Provider<T>(
|
||||
/// 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()
|
||||
})
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
use wasm_bindgen::UnwrapThrowExt;
|
||||
|
||||
#[macro_export]
|
||||
/// Use for tracing property
|
||||
macro_rules! tracing_props {
|
||||
@@ -9,9 +11,8 @@ macro_rules! tracing_props {
|
||||
);
|
||||
};
|
||||
($($prop:tt),+ $(,)?) => {
|
||||
#[cfg(any(debug_assertions, feature = "ssr"))]
|
||||
{
|
||||
use ::leptos::leptos_dom::tracing_property::{Match, DebugMatch, DefaultMatch};
|
||||
use ::leptos::leptos_dom::tracing_property::{Match, SerializeMatch, DefaultMatch};
|
||||
let mut props = String::from('[');
|
||||
$(
|
||||
let prop = (&&Match {
|
||||
@@ -39,17 +40,29 @@ pub struct Match<T> {
|
||||
pub value: std::cell::Cell<Option<T>>,
|
||||
}
|
||||
|
||||
pub trait DebugMatch {
|
||||
pub trait SerializeMatch {
|
||||
type Return;
|
||||
fn spez(&self) -> Self::Return;
|
||||
}
|
||||
impl<T: core::fmt::Debug> DebugMatch for &Match<&T> {
|
||||
impl<T: serde::Serialize> SerializeMatch for &Match<&T> {
|
||||
type Return = String;
|
||||
fn spez(&self) -> Self::Return {
|
||||
let name = self.name;
|
||||
let debug_value =
|
||||
format!("{:?}", self.value.get().unwrap()).replace('"', r#"\""#);
|
||||
format!(r#"{{"name": "{name}", "value": "{debug_value}"}}"#,)
|
||||
|
||||
// suppresses warnings when serializing signals into props
|
||||
#[cfg(debug_assertions)]
|
||||
let prev = leptos_reactive::SpecialNonReactiveZone::enter();
|
||||
|
||||
let value = serde_json::to_string(self.value.get().unwrap_throw())
|
||||
.map_or_else(
|
||||
|err| format!(r#"{{"name": "{name}", "error": "{err}"}}"#),
|
||||
|value| format!(r#"{{"name": "{name}", "value": {value}}}"#),
|
||||
);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
leptos_reactive::SpecialNonReactiveZone::exit(prev);
|
||||
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,9 +74,7 @@ impl<T> DefaultMatch for Match<&T> {
|
||||
type Return = String;
|
||||
fn spez(&self) -> Self::Return {
|
||||
let name = self.name;
|
||||
format!(
|
||||
r#"{{"name": "{name}", "value": "[value does not implement Debug]"}}"#
|
||||
)
|
||||
format!(r#"{{"name": "{name}", "value": "[unserializable value]"}}"#)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +87,7 @@ fn match_primitive() {
|
||||
value: std::cell::Cell::new(Some(&test)),
|
||||
})
|
||||
.spez();
|
||||
assert_eq!(prop, r#"{"name": "test", "value": "\"string\""}"#);
|
||||
assert_eq!(prop, r#"{"name": "test", "value": "string"}"#);
|
||||
|
||||
// &str
|
||||
let test = "string";
|
||||
@@ -85,7 +96,7 @@ fn match_primitive() {
|
||||
value: std::cell::Cell::new(Some(&test)),
|
||||
})
|
||||
.spez();
|
||||
assert_eq!(prop, r#"{"name": "test", "value": "\"string\""}"#);
|
||||
assert_eq!(prop, r#"{"name": "test", "value": "string"}"#);
|
||||
|
||||
// u128
|
||||
let test: u128 = 1;
|
||||
@@ -127,7 +138,7 @@ fn match_primitive() {
|
||||
#[test]
|
||||
fn match_serialize() {
|
||||
use serde::Serialize;
|
||||
#[derive(Debug)]
|
||||
#[derive(Serialize)]
|
||||
struct CustomStruct {
|
||||
field: &'static str,
|
||||
}
|
||||
@@ -138,10 +149,7 @@ fn match_serialize() {
|
||||
value: std::cell::Cell::new(Some(&test)),
|
||||
})
|
||||
.spez();
|
||||
assert_eq!(
|
||||
prop,
|
||||
r#"{"name": "test", "value": "CustomStruct { field: \"field\" }"}"#
|
||||
);
|
||||
assert_eq!(prop, r#"{"name": "test", "value": {"field":"field"}}"#);
|
||||
// Verification of ownership
|
||||
assert_eq!(test.field, "field");
|
||||
}
|
||||
@@ -162,7 +170,7 @@ fn match_no_serialize() {
|
||||
.spez();
|
||||
assert_eq!(
|
||||
prop,
|
||||
r#"{"name": "test", "value": "[value does not implement Debug]"}"#
|
||||
r#"{"name": "test", "value": "[unserializable value]"}"#
|
||||
);
|
||||
// Verification of ownership
|
||||
assert_eq!(test.field, "field");
|
||||
|
||||
@@ -84,7 +84,29 @@ use std::any::{Any, TypeId};
|
||||
/// that was provided in `<Parent/>`, meaning that the second `<Child/>` 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! {
|
||||
/// <Provider value="child_context">
|
||||
/// <div>{format!("child (context: {context})")}</div>
|
||||
/// </Provider>
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ### Alternate Solution
|
||||
///
|
||||
/// This can also be solved by introducing some additional reactivity. In this case, it’s simplest
|
||||
/// to simply make the body of `<Child/>` a function, which means it will be wrapped in a
|
||||
/// new reactive node when rendered:
|
||||
/// ```rust
|
||||
|
||||
@@ -1247,9 +1247,7 @@ where
|
||||
}
|
||||
#[cfg(all(feature = "hydrate", debug_assertions))]
|
||||
{
|
||||
if self.serializable != ResourceSerialization::Local
|
||||
&& !SpecialNonReactiveZone::is_inside()
|
||||
{
|
||||
if self.serializable != ResourceSerialization::Local {
|
||||
crate::macros::debug_warn!(
|
||||
"At {location}, you are reading a resource in \
|
||||
`hydrate` mode outside a <Suspense/> or \
|
||||
|
||||
Reference in New Issue
Block a user