Is it safe to ignore some properties from PartialEq for a struct component. #3739
-
I have a Struct Component which switches itself between displaying text as a normal div/span and being an input text box when clicked. The parent controls the final text when the edit is committed, but the component controls its stated during editing. This isn't quite a minimal example, but I've tried to cut it down to the most relevant bits: #[derive(Debug, Properties)]
pub struct Props {
/// Last committed value.
pub value: AttrValue,
// ...
// ... Other properites which also affect the output of view
// ...
/// Commit an updated value.
pub on_commit: Callback<AttrValue>,
}
pub enum Msg {
/// Message during editing to update the edited text.
UpdateInput { input: AttrValue },
/// Message while not editing to start editing.
StartEdit,
/// Message to finish editing.
FinishEdit,
/// Cancel editing without changing the value.
Cancel,
}
/// Helper to display some text with click-to-edit.
pub struct ClickEdit {
/// Pending edit text if clock speed is being changed.
edit_text: Option<AttrValue>,
/// Whether we did focus since last committing an edit.
did_focus: bool,
/// Input to focus on editing.
input: NodeRef,
// Memoized callbacks:
oninput: Callback<InputEvent>,
onkeyup: Callback<KeyboardEvent>,
onblur: Callback<FocusEvent>,
onsubmit: Callback<SubmitEvent>,
onclick: Callback<MouseEvent>,
}
impl Component for ClickEdit {
type Message = Msg;
type Properties = Props;
fn create(ctx: &Context<Self>) -> Self {
let link = ctx.link();
ClickEdit {
edit_text: None,
did_focus: true,
input: NodeRef::default(),
oninput: link.callback(|input| Msg::UpdateInput {
input: get_value_from_input_event(input),
}),
onkeyup: link.batch_callback(|e: KeyboardEvent| match &*e.key() {
"Esc" | "Escape" => Some(Msg::Cancel),
_ => None,
}),
onblur: link.callback(|_| Msg::FinishEdit),
onsubmit: link.callback(|e: SubmitEvent| {
e.prevent_default();
Msg::FinishEdit
}),
onclick: link.callback(|_| Msg::StartEdit),
}
}
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
match msg {
Msg::UpdateInput { input } => {
self.edit_text = Some(input);
true
}
Msg::StartEdit => {
self.edit_text = Some(ctx.props().value.clone());
self.did_focus = false;
true
}
Msg::FinishEdit => {
if let Some(edit_text) = self.edit_text.take() {
ctx.props().on_commit.emit(edit_text);
true
}
}
Msg::Cancel => {
self.edit_text = None;
true
}
}
}
fn view(&self, ctx: &Context<Self>) -> Html {
let Props {
value,
..
} = ctx.props();
let class = self.class.clone();
if let Some(value) = self.edit_text.clone() {
let oninput = self.oninput.clone();
let onkeyup = self.onkeyup.clone();
let onblur = self.onblur.clone();
let onsubmit = self.onsubmit.clone();
html! {
<form {onsubmit}>
<input type="text" value={&value}
{oninput} {onblur} {onkeyup} ref={&self.input} />
</form>
}
} else {
let onclick = self.onclick.clone();
html! {
<div {onclick}>{value}</div>
}
}
}
fn rendered(&mut self, _ctx: &Context<Self>, _first_render: bool) {
if !self.did_focus {
if let Some(input) = self.input.cast::<HtmlInputElement>() {
if let Err(e) = input.focus() {
warn!("Failed to focus input: {:?}", e);
}
input.select();
self.did_focus = true;
}
}
}
} What's important here is that the My concern is that I don't know if Yew will skip updating entirely if two old props and new props compare equal, or if it will attach the new props to the context but skip calling I could of course implement custom comparison logic in So I just want to know if Yew guarantees that a struct component's Context includes the most up to date properties, even if those properties compared equal to the old properties according to |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 2 replies
-
Yew compares with the existing props and only replaces if they compare unequal. In this case, Small comment about the concern about duplicating work: The relevant code section is monomorphized per component, so I would think that the compiler is smart enough to inline Relevant code: yew/packages/yew/src/html/component/lifecycle.rs Lines 211 to 216 in 2e464ed |
Beta Was this translation helpful? Give feedback.
Yew compares with the existing props and only replaces if they compare unequal. In this case,
changed
is then called to figure out if the component needs to re-render. Note that this callback also gives you access to the old props. So the correct way to avoid a re-render is to implementchanged
here.Small comment about the concern about duplicating work: The relevant code section is monomorphized per component, so I would think that the compiler is smart enough to inline
changed
in most cases and remove the duplicate checks in a lot of cases.Relevant code:
yew/packages/yew/src/html/component/lifecycle.rs
Lines 211 to 216 in 2e464ed