-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reliable use_reducer
dispatch and use_state
setter
#2126
Conversation
Visit the preview URL for this PR (updated for commit f800148): https://yew-rs--pr2126-stale-value-ptcefc0e.web.app (expires Thu, 18 Nov 2021 11:28:23 GMT) 🔥 via Firebase Hosting GitHub Action 🌎 |
Old Approach: struct CounterState {
counter: i32,
}
let counter = use_reducer_with_init(
|prev: std::rc::Rc<CounterState>, action: i32| CounterState {
counter: prev.counter + action,
},
0,
|initial: i32| CounterState {
counter: initial + 10,
},
); New Approach: struct CounterState {
counter: i32,
}
impl Default for CounterState {
fn default() -> Self {
Self { counter: 10 }
}
}
impl Reducible for CounterState {
type Action = i32;
fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {
Self {
counter: self.counter + action,
}
.into()
}
}
let counter = use_reducer(CounterState::default); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just some documentation grammar
Co-authored-by: Simon <[email protected]>
Co-authored-by: Simon <[email protected]>
Co-authored-by: Simon <[email protected]>
Description
As described in #2112,
use_state
's value is susceptible to outdated values and causes theset_if_neq
to be unreliable.The reducer function is also susceptible to the same problem as it is tied to the dispatch function with the current implementation.
The value going stale problem mostly can be solved by adapting established patterns from the React world but it still requires the setter and dispatch function to work reliably (Or functions like their counterpart in React).
This PR takes a different approach which makes the reducer function to be static to avoid it becoming stale or attempting to pass a different reducer function between renders.
(Defining the reducer function outside of the component is a common practice in React and attempting to update another state while the component is rendering will result in an error in React.)
This PR consists of the following change:
use_reducer
now accepts 1 argument which is an initialiser function.use_reducer
now requires to implementReducible
trait which providesAction
andreduce
.use_reducer_eq
which only re-renders ifprev_state != next_state
.use_state
is implemented withuse_reducer
.use_state_eq
which only re-renders ifprev_state != next_state
(Implemented withuse_reducer_eq
).UseStateHandle
andUseReducerHandle
only implementsPartialEq
ifT: PartialEq
.dispatcher
andsetter
method. It always implementsPartialEq
even ifT: !PartialEq
. This can be passed as a prop / context if T is notPartialEq
.Fixes #2112 (in conjunction with #2125).
Checklist
cargo make pr-flow