use_reducer no longer re-renders on identity dispatches#
use_reducer now skips re-rendering when the reducer returns the same Rc (checked by pointer equality). Previously, every dispatch triggered a re-render regardless.
If your reducer has a code path that returns self unchanged and you relied on that causing a re-render, replace it with use_force_update:
Before
After
pubenumAction{
Increment,
ForceRefresh,}structState{count:u32,
}implReducible forState{typeAction= Action;fnreduce(self: Rc<Self>, action:Self::Action)->Rc<Self>{match action {Action::Increment =>Rc::new(Self{
count:self.count +1,}),// This no longer triggers a re-render in 0.23!
Action::ForceRefresh =>self,}}}#[component]pubfnApp()-> Html{use_effect(||{tracing::info!("This cursed component does some effects on render");});let state =use_reducer(||State { count:0});html!{<div><p>{ state.count }</p><button onclick={let state = state.clone();move|_| state.dispatch(Action::Increment)}>{"+1"}</button><button onclick={move|_| state.dispatch(Action::ForceRefresh)}>{"Refresh"}</button></div>}}
pubenumAction{
Increment,}structState{count:u32,
}implReducible forState{typeAction= Action;fnreduce(self: Rc<Self>, action:Self::Action)->Rc<Self>{match action {Action::Increment =>Rc::new(Self{
count:self.count +1,}),}}}#[component]pubfnApp()-> Html{use_effect(||{tracing::info!("This cursed component does some effects on render");});let state =use_reducer(||State { count:0});let trigger =use_force_update();html!{<div><p>{ state.count }</p><button onclick={move|_| state.dispatch(Action::Increment)}>{"+1"}</button><button onclick={move|_| trigger.force_update()}>{"Refresh"}</button></div>}}