mirror of
https://github.com/leptos-rs/leptos.git
synced 2025-12-27 09:54:41 -05:00
fix: tweak bounds on For for backwards-compat (#3663)
This commit is contained in:
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -1808,6 +1808,7 @@ dependencies = [
|
||||
"send_wrapper",
|
||||
"serde_json",
|
||||
"server_fn",
|
||||
"tachys",
|
||||
"tokio",
|
||||
"tracing",
|
||||
]
|
||||
@@ -1829,6 +1830,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"server_fn",
|
||||
"tachys",
|
||||
"tokio",
|
||||
"tower",
|
||||
"tower-http",
|
||||
@@ -3450,6 +3452,8 @@ dependencies = [
|
||||
"reactive_stores",
|
||||
"rustc-hash 2.1.1",
|
||||
"send_wrapper",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sledgehammer_bindgen",
|
||||
"sledgehammer_utils",
|
||||
"slotmap",
|
||||
|
||||
@@ -21,6 +21,7 @@ leptos_macro = { workspace = true, features = ["actix"] }
|
||||
leptos_meta = { workspace = true, features = ["nonce"] }
|
||||
leptos_router = { workspace = true, features = ["ssr"] }
|
||||
server_fn = { workspace = true, features = ["actix"] }
|
||||
tachys = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
parking_lot = "0.12.3"
|
||||
tracing = { version = "0.1", optional = true }
|
||||
@@ -33,7 +34,7 @@ once_cell = "1"
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
||||
[features]
|
||||
islands-router = []
|
||||
islands-router = ["tachys/islands"]
|
||||
tracing = ["dep:tracing"]
|
||||
|
||||
[package.metadata.cargo-all-features]
|
||||
|
||||
@@ -22,6 +22,7 @@ leptos_macro = { workspace = true, features = ["axum"] }
|
||||
leptos_meta = { workspace = true, features = ["ssr", "nonce"] }
|
||||
leptos_router = { workspace = true, features = ["ssr"] }
|
||||
leptos_integration_utils = { workspace = true }
|
||||
tachys = { workspace = true }
|
||||
once_cell = "1"
|
||||
parking_lot = "0.12.3"
|
||||
tokio = { version = "1.43", default-features = false }
|
||||
@@ -36,7 +37,7 @@ tokio = { version = "1.43", features = ["net", "rt-multi-thread"] }
|
||||
[features]
|
||||
wasm = []
|
||||
default = ["tokio/fs", "tokio/sync", "tower-http/fs", "tower/util"]
|
||||
islands-router = []
|
||||
islands-router = ["tachys/islands"]
|
||||
tracing = ["dep:tracing"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
|
||||
@@ -6,7 +6,10 @@ use reactive_graph::{
|
||||
traits::Set,
|
||||
};
|
||||
use std::hash::Hash;
|
||||
use tachys::{reactive_graph::OwnedView, view::keyed::keyed};
|
||||
use tachys::{
|
||||
reactive_graph::OwnedView,
|
||||
view::keyed::{keyed, SerializableKey},
|
||||
};
|
||||
|
||||
/// Iterates over children and displays them, keyed by the `key` function given.
|
||||
///
|
||||
@@ -121,7 +124,7 @@ where
|
||||
EF: Fn(T) -> N + Send + Clone + 'static,
|
||||
N: IntoView + 'static,
|
||||
KF: Fn(&T) -> K + Send + Clone + 'static,
|
||||
K: Eq + Hash + ToString + 'static,
|
||||
K: Eq + Hash + SerializableKey + 'static,
|
||||
T: Send + 'static,
|
||||
{
|
||||
// this takes the owner of the For itself
|
||||
@@ -195,7 +198,7 @@ where
|
||||
EF: Fn(ReadSignal<usize>, T) -> N + Send + Clone + 'static,
|
||||
N: IntoView + 'static,
|
||||
KF: Fn(&T) -> K + Send + Clone + 'static,
|
||||
K: Eq + Hash + ToString + 'static,
|
||||
K: Eq + Hash + SerializableKey + 'static,
|
||||
T: Send + 'static,
|
||||
{
|
||||
// this takes the owner of the For itself
|
||||
@@ -218,6 +221,7 @@ where
|
||||
};
|
||||
move || keyed(each(), key.clone(), children.clone())
|
||||
}
|
||||
|
||||
/*
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
@@ -162,6 +162,8 @@ sledgehammer_bindgen = { version = "0.6.0", features = [
|
||||
], optional = true }
|
||||
sledgehammer_utils = { version = "0.3.1", optional = true }
|
||||
tracing = { version = "0.1.41", optional = true }
|
||||
serde = { version = "1", optional = true }
|
||||
serde_json = { version = "1", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
tokio-test = "0.4.4"
|
||||
@@ -172,7 +174,7 @@ default = ["testing"]
|
||||
delegation = [] # enables event delegation
|
||||
error-hook = []
|
||||
hydrate = []
|
||||
islands = []
|
||||
islands = ["dep:serde", "dep:serde_json"]
|
||||
ssr = []
|
||||
oco = ["dep:oco_ref"]
|
||||
nightly = ["reactive_graph/nightly"]
|
||||
|
||||
@@ -50,6 +50,39 @@ where
|
||||
view_fn: VF,
|
||||
}
|
||||
|
||||
/// By default, keys used in for keyed iteration do not need to be serializable.
|
||||
///
|
||||
/// However, for some scenarios (like the “islands routing” mode that mixes server-side
|
||||
/// rendering with client-side navigation) it is useful to have serializable keys.
|
||||
///
|
||||
/// When the `islands` feature is not enabled, this trait is implemented by all types.
|
||||
///
|
||||
/// When the `islands` features is enabled, this is automatically implemented for all types
|
||||
/// that implement [`Serialize`](serde::Serialize), and can be manually implemented otherwise.
|
||||
pub trait SerializableKey {
|
||||
/// Serializes the key to a unique string.
|
||||
///
|
||||
/// The string can have any value, as long as it is idempotent (i.e., serializing the same key
|
||||
/// multiple times will give the same value).
|
||||
fn ser_key(&self) -> String;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "islands"))]
|
||||
impl<T> SerializableKey for T {
|
||||
fn ser_key(&self) -> String {
|
||||
panic!(
|
||||
"SerializableKey called without the `islands` feature enabled. \
|
||||
Something has gone wrong."
|
||||
);
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "islands")]
|
||||
impl<T: serde::Serialize> SerializableKey for T {
|
||||
fn ser_key(&self) -> String {
|
||||
serde_json::to_string(self).expect("failed to serialize key")
|
||||
}
|
||||
}
|
||||
|
||||
/// Retained view state for a keyed list.
|
||||
pub struct KeyedState<K, VFS, V>
|
||||
where
|
||||
@@ -66,7 +99,7 @@ where
|
||||
impl<T, I, K, KF, VF, VFS, V> Render for Keyed<T, I, K, KF, VF, VFS, V>
|
||||
where
|
||||
I: IntoIterator<Item = T>,
|
||||
K: Eq + Hash + ToString + 'static,
|
||||
K: Eq + Hash + SerializableKey + 'static,
|
||||
KF: Fn(&T) -> K,
|
||||
V: Render,
|
||||
VF: Fn(usize, T) -> (VFS, V),
|
||||
@@ -132,7 +165,7 @@ where
|
||||
impl<T, I, K, KF, VF, VFS, V> AddAnyAttr for Keyed<T, I, K, KF, VF, VFS, V>
|
||||
where
|
||||
I: IntoIterator<Item = T> + Send + 'static,
|
||||
K: Eq + Hash + ToString + 'static,
|
||||
K: Eq + Hash + SerializableKey + 'static,
|
||||
KF: Fn(&T) -> K + Send + 'static,
|
||||
V: RenderHtml,
|
||||
V: 'static,
|
||||
@@ -185,7 +218,7 @@ where
|
||||
impl<T, I, K, KF, VF, VFS, V> RenderHtml for Keyed<T, I, K, KF, VF, VFS, V>
|
||||
where
|
||||
I: IntoIterator<Item = T> + Send + 'static,
|
||||
K: Eq + Hash + ToString + 'static,
|
||||
K: Eq + Hash + SerializableKey + 'static,
|
||||
KF: Fn(&T) -> K + Send + 'static,
|
||||
V: RenderHtml + 'static,
|
||||
VF: Fn(usize, T) -> (VFS, V) + Send + 'static,
|
||||
@@ -261,7 +294,7 @@ where
|
||||
for (index, item) in self.items.into_iter().enumerate() {
|
||||
let branch_name = mark_branches.then(|| {
|
||||
let key = (self.key_fn)(&item);
|
||||
let key = key.to_string();
|
||||
let key = key.ser_key();
|
||||
format!("item-{key}")
|
||||
});
|
||||
let (_, item) = (self.view_fn)(index, item);
|
||||
|
||||
Reference in New Issue
Block a user