-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Description
Problem
In Yew 0.22.1, passing a UseStateHandle<T> as a prop to a child component no longer triggers re-renders when the state is updated. This is caused by #3988 cc @Madoshakalaka (Very cool feature, just unfortunate that it breaks this for me.)
That PR changed the behavior of UseStateHandle so that dereferencing it always fetches the latest state. While this successfully fixes stale closures, it breaks the PartialEq implementation for UseStateHandle.
(Even if this is eventually the intended behavior, this is a breaking change in a patch release. The example code below works in 0.22.0 but breaks in 0.22.1.)
When a parent component re-renders and passes a new handle to the child, Yew compares the props: **old_handle == **new_handle. Because both handles now fetch the live state, this effectively evaluates to new_state == new_state. This always returns true, causing Yew to incorrectly assume the props haven't changed and skip rendering the child component.
I acknowledge that passing the handle directly like this isn't always recommended, but it has been supported by yew for a long time and this breaks that behavior.
Steps To Reproduce
Steps to reproduce the behavior:
- Create a parent component that initializes state with
use_state. - Pass that
UseStateHandleas a prop to a child component. - Update the state (either from the parent or the child).
- Observe that the parent re-renders, but the child component's UI remains frozen because it skips the render step.
Here is a minimal reproducible example:
use yew::prelude::*;
#[derive(Properties, PartialEq)]
pub struct ChildProps {
pub handle: UseStateHandle<i32>,
}
#[component]
pub fn Child(props: &ChildProps) -> Html {
let onclick = {
let handle = props.handle.clone();
Callback::from(move |_| {
// In 0.22.1, this correctly updates the state, but the child UI won't update
handle.set(*handle + 1);
})
};
html! {
<div style="padding: 10px; border: 1px solid red;">
<p>{ "Child sees: " }{ *props.handle }</p>
<button {onclick}>{ "Increment" }</button>
</div>
}
}
#[component]
pub fn App() -> Html {
let state = use_state(|| 0);
html! {
<div style="padding: 10px; border: 1px solid blue;">
<p>{ "Parent sees: " }{ *state }</p>
<Child handle={state} />
</div>
}
}Expected behavior
When the state is updated, PartialEq for UseStateHandle should correctly evaluate to false so the child component re-renders and displays the updated state, matching the behavior of Yew 0.22.0.
Screenshots
N/A - The UI simply fails to update the child component's DOM.
Environment:
- Yew version: 0.22.1
- Rust version: 1.93.1
- Target, if relevant:
wasm32-unknown-unknown - Build tool, if relevant:
trunk
Questionnaire
- I'm interested in fixing this myself but don't know where to start
- I would like to fix and I have a solution
- I don't have time to fix this right now, but maybe later