I am making a web app using Yew Rust as front end. The structs User
, Post
, Vote
are wrappers over JSON objects from the backend. I want to request several PostCards from the backend, format them using the html!
macro and render them.
The problem is that it always renders the first element (even if I have 5 elements in self.post_cards
, the first one is rendered 5 times). Iterating over self.post_cards
before the html!
and logging data about the postcard, I see that the data is different (the same as the data sent from the backend, so JSON parsing works).
This is how I add data to self.post_cards
:
#[derive(Clone)]
pub struct Index {
post_cards: Vec<PostCard>,
can_request: bool,
current_index: u32,
}
...
if let Value::Array(v) = &json["data"] {
for value in v {
self.post_cards.push(PostCard::from_json(value.clone()));
}
}
View method:
fn view(&self, ctx: &Context<Self>) -> Html {
html! {
<>
<Navbar/>
<div>
{
self.post_cards.iter().map(|pc| {
html!{
<PostCard
post={pc.post.clone()}
user={pc.user.clone()}
vote={pc.vote.clone()}
/>
}
}).collect::<Html>()
}
</div>
<Footer/>
</>
}
}
#[derive(Clone, PartialEq)]
pub struct PostCard {
pub post: Post,
pub user: User,
pub vote: Vote,
}
I am using yew 0.20.0 and rustc 1.67.1
I also tried a more hard coded approach: to render the first item if the size is >0, render the second item if the size is >1 and it worked, but I would rather not use this approach as the postcard count can get pretty big.
Edit 1:
It seems that the PostCard component doesn't properly create new items. By adding a log in html!
and PostCard
create()
method I saw that the values were different.
self.post_cards.iter().map(|pc| {
log!("index.rs html!", pc.post.clone().text);
html!{
<PostCard
post={pc.post.clone()}
user={pc.user.clone()}
vote={pc.vote.clone()}
/>
}
}).collect::<Html>()
impl Component for PostCard {
...
fn create(ctx: &Context<Self>) -> Self {
log!("=== PostCard created === ");
log!("PostCard post text\n", ctx.props().post.text.clone());
PostCard {
post: ctx.props().post.clone(),
user: ctx.props().user.clone(),
vote: ctx.props().vote.clone(),
}
}
...
}
So the issue now is with the way each element is created, is there a different way of doing this?
Edit 2:
I added the changed()
method to the PostCard
struct and now everything works as intended, however is this the correct way to render vectors of components?
fn changed(&mut self, ctx: &Context<Self>, _old_props: &Self::Properties) -> bool {
self.post = ctx.props().post.clone();
self.user = ctx.props().user.clone();
self.vote = ctx.props().vote.clone();
true
}