From e7e18b1995bfec3fafddc140354618e584e95544 Mon Sep 17 00:00:00 2001 From: Greg Johnston Date: Fri, 26 Dec 2025 11:26:05 -0500 Subject: [PATCH] fix: correctly read resources inside `` children (closes #4503) (#4504) --- tachys/src/view/keyed.rs | 104 ++++++++++++++++++++++++++++----------- 1 file changed, 74 insertions(+), 30 deletions(-) diff --git a/tachys/src/view/keyed.rs b/tachys/src/view/keyed.rs index 29f552526..d59c1d3e0 100644 --- a/tachys/src/view/keyed.rs +++ b/tachys/src/view/keyed.rs @@ -23,14 +23,32 @@ pub fn keyed( ) -> Keyed where I: IntoIterator, - K: Eq + Hash + 'static, + K: Eq + Hash + SerializableKey + 'static, KF: Fn(&T) -> K, V: Render, VF: Fn(usize, T) -> (VFS, V), VFS: Fn(usize), { Keyed { - items, + #[cfg(not(feature = "ssr"))] + items: Some(items), + #[cfg(feature = "ssr")] + items: None, + #[cfg(feature = "ssr")] + ssr_items: items + .into_iter() + .enumerate() + .map(|(i, t)| { + let key = if cfg!(feature = "islands") { + let key = (key_fn)(&t); + key.ser_key() + } else { + String::new() + }; + let (_, view) = (view_fn)(i, t); + (key, view) + }) + .collect::>(), key_fn, view_fn, } @@ -45,7 +63,9 @@ where VF: Fn(usize, T) -> (VFS, V), VFS: Fn(usize), { - items: I, + items: Option, + #[cfg(feature = "ssr")] + ssr_items: Vec<(String, V)>, key_fn: KF, view_fn: VF, } @@ -106,14 +126,13 @@ where VFS: Fn(usize), { type State = KeyedState; - // TODO fallible state and try_build()/try_rebuild() here fn build(self) -> Self::State { - let items = self.items.into_iter(); + let items = self.items.into_iter().flatten(); let (capacity, _) = items.size_hint(); let mut hashed_items = FxIndexSet::with_capacity_and_hasher(capacity, Default::default()); - let mut rendered_items = Vec::new(); + let mut rendered_items = Vec::with_capacity(capacity); for (index, item) in items.enumerate() { hashed_items.insert((self.key_fn)(&item)); let (set_index, view) = (self.view_fn)(index, item); @@ -134,7 +153,7 @@ where hashed_items, ref mut rendered_items, } = state; - let new_items = self.items.into_iter(); + let new_items = self.items.into_iter().flatten(); let (capacity, _) = new_items.size_hint(); let mut new_hashed_items = FxIndexSet::with_capacity_and_hasher(capacity, Default::default()); @@ -198,6 +217,8 @@ where { let Keyed { items, + #[cfg(feature = "ssr")] + ssr_items, key_fn, view_fn, } = self; @@ -205,6 +226,11 @@ where Keyed { items, key_fn, + #[cfg(feature = "ssr")] + ssr_items: ssr_items + .into_iter() + .map(|(k, v)| (k, v.add_any_attr(attr.clone()))) + .collect(), view_fn: Box::new(move |index, item| { let (index, view) = view_fn(index, item); (index, view.add_any_attr(attr.clone())) @@ -229,21 +255,39 @@ where const MIN_LENGTH: usize = 0; fn dry_resolve(&mut self) { - // TODO... + #[cfg(feature = "ssr")] + for view in &mut self.ssr_items { + view.dry_resolve(); + } } async fn resolve(self) -> Self::AsyncOutput { - futures::future::join_all(self.items.into_iter().enumerate().map( - |(index, item)| { - let (_, view) = (self.view_fn)(index, item); - view.resolve() - }, - )) - .await - .into_iter() - .collect::>() + #[cfg(feature = "ssr")] + { + futures::future::join_all( + self.ssr_items.into_iter().map(|(_, view)| view.resolve()), + ) + .await + .into_iter() + .collect::>() + } + #[cfg(not(feature = "ssr"))] + { + futures::future::join_all( + self.items.into_iter().flatten().enumerate().map( + |(index, item)| { + let (_, view) = (self.view_fn)(index, item); + view.resolve() + }, + ), + ) + .await + .into_iter() + .collect::>() + } } + #[allow(unused)] fn to_html_with_buf( self, buf: &mut String, @@ -255,8 +299,9 @@ where if mark_branches && escape { buf.open_branch("for"); } - for (index, item) in self.items.into_iter().enumerate() { - let (_, item) = (self.view_fn)(index, item); + + #[cfg(feature = "ssr")] + for item in self.ssr_items { if mark_branches && escape { buf.open_branch("item"); } @@ -278,6 +323,7 @@ where buf.push_str(""); } + #[allow(unused)] fn to_html_async_with_buf( self, buf: &mut StreamBuilder, @@ -289,13 +335,10 @@ where if mark_branches && escape { buf.open_branch("for"); } - for (index, item) in self.items.into_iter().enumerate() { - let branch_name = mark_branches.then(|| { - let key = (self.key_fn)(&item); - let key = key.ser_key(); - format!("item-{key}") - }); - let (_, item) = (self.view_fn)(index, item); + + #[cfg(feature = "ssr")] + for (key, item) in self.ssr_items { + let branch_name = mark_branches.then(|| format!("item-{key}")); if mark_branches && escape { buf.open_branch(branch_name.as_ref().unwrap()); } @@ -311,6 +354,7 @@ where } *position = Position::NextChild; } + if mark_branches && escape { buf.close_branch("for"); } @@ -334,11 +378,11 @@ where .expect("parent of keyed list should be an element"); // build list - let items = self.items.into_iter(); + let items = self.items.into_iter().flatten(); let (capacity, _) = items.size_hint(); let mut hashed_items = FxIndexSet::with_capacity_and_hasher(capacity, Default::default()); - let mut rendered_items = Vec::new(); + let mut rendered_items = Vec::with_capacity(capacity); for (index, item) in items.enumerate() { hashed_items.insert((self.key_fn)(&item)); let (set_index, view) = (self.view_fn)(index, item); @@ -373,11 +417,11 @@ where .expect("parent of keyed list should be an element"); // build list - let items = self.items.into_iter(); + let items = self.items.into_iter().flatten(); let (capacity, _) = items.size_hint(); let mut hashed_items = FxIndexSet::with_capacity_and_hasher(capacity, Default::default()); - let mut rendered_items = Vec::new(); + let mut rendered_items = Vec::with_capacity(capacity); for (index, item) in items.enumerate() { hashed_items.insert((self.key_fn)(&item)); let (set_index, view) = (self.view_fn)(index, item);