Skip to content

Commit

Permalink
Make Component::change impl mandatory
Browse files Browse the repository at this point in the history
  • Loading branch information
jstarry committed Apr 4, 2020
1 parent 039c860 commit 60e5ab2
Show file tree
Hide file tree
Showing 13 changed files with 266 additions and 142 deletions.
4 changes: 4 additions & 0 deletions crates/macro/src/lib.rs
Expand Up @@ -31,6 +31,10 @@
//! # unimplemented!()
//! # }
//! #
//! # fn change(&mut self, props: Self::Properties) -> ShouldRender {
//! # unimplemented!()
//! # }
//! #
//! # fn view(&self) -> Html {
//! #
//! // ...
Expand Down
9 changes: 9 additions & 0 deletions crates/macro/tests/macro/html-component-fail.rs
Expand Up @@ -21,6 +21,9 @@ impl Component for Child {
fn update(&mut self, _: Self::Message) -> ShouldRender {
unimplemented!()
}
fn change(&mut self, _: Self::Properties) -> ShouldRender {
unimplemented!()
}
fn view(&self) -> Html {
unimplemented!()
}
Expand All @@ -42,6 +45,9 @@ impl Component for ChildContainer {
fn update(&mut self, _: Self::Message) -> ShouldRender {
unimplemented!()
}
fn change(&mut self, _: Self::Properties) -> ShouldRender {
unimplemented!()
}
fn view(&self) -> Html {
unimplemented!()
}
Expand All @@ -61,6 +67,9 @@ impl Component for Generic<String> {
fn update(&mut self, _: Self::Message) -> ShouldRender {
unimplemented!()
}
fn change(&mut self, _: Self::Properties) -> ShouldRender {
unimplemented!()
}
fn view(&self) -> Html {
unimplemented!()
}
Expand Down
256 changes: 128 additions & 128 deletions crates/macro/tests/macro/html-component-fail.stderr

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions crates/macro/tests/macro/html-component-pass.rs
Expand Up @@ -19,6 +19,9 @@ impl Component for Generic<String> {
fn update(&mut self, _: Self::Message) -> ShouldRender {
unimplemented!()
}
fn change(&mut self, _: Self::Properties) -> ShouldRender {
unimplemented!()
}
fn view(&self) -> Html {
unimplemented!()
}
Expand All @@ -34,6 +37,9 @@ impl Component for Generic<Vec<String>> {
fn update(&mut self, _: Self::Message) -> ShouldRender {
unimplemented!()
}
fn change(&mut self, _: Self::Properties) -> ShouldRender {
unimplemented!()
}
fn view(&self) -> Html {
unimplemented!()
}
Expand All @@ -57,6 +63,9 @@ impl Component for Container {
fn update(&mut self, _: Self::Message) -> ShouldRender {
unimplemented!()
}
fn change(&mut self, _: Self::Properties) -> ShouldRender {
unimplemented!()
}
fn view(&self) -> Html {
unimplemented!()
}
Expand Down Expand Up @@ -113,6 +122,9 @@ impl Component for Child {
fn update(&mut self, _: Self::Message) -> ShouldRender {
unimplemented!()
}
fn change(&mut self, _: Self::Properties) -> ShouldRender {
unimplemented!()
}
fn view(&self) -> Html {
unimplemented!()
}
Expand All @@ -129,6 +141,9 @@ impl Component for AltChild {
fn update(&mut self, _: Self::Message) -> ShouldRender {
unimplemented!()
}
fn change(&mut self, _: Self::Properties) -> ShouldRender {
unimplemented!()
}
fn view(&self) -> Html {
unimplemented!()
}
Expand All @@ -152,6 +167,9 @@ impl Component for ChildContainer {
fn update(&mut self, _: Self::Message) -> ShouldRender {
unimplemented!()
}
fn change(&mut self, _: Self::Properties) -> ShouldRender {
unimplemented!()
}
fn view(&self) -> Html {
unimplemented!()
}
Expand Down
1 change: 1 addition & 0 deletions src/components/select.rs
Expand Up @@ -14,6 +14,7 @@
//!# type Message = ();type Properties = ();
//!# fn create(props: Self::Properties,link: ComponentLink<Self>) -> Self {unimplemented!()}
//!# fn update(&mut self,msg: Self::Message) -> bool {unimplemented!()}
//!# fn change(&mut self, _: Self::Properties) -> bool {unimplemented!()}
//!# fn view(&self) -> Html {unimplemented!()}}
//! impl ToString for Scene {
//! fn to_string(&self) -> String {
Expand Down
84 changes: 71 additions & 13 deletions src/html/mod.rs
Expand Up @@ -31,13 +31,41 @@ cfg_if! {
/// This type indicates that component should be rendered again.
pub type ShouldRender = bool;

/// An interface of a UI-component. Uses `self` as a model.
/// Components are the basic building blocks of the UI in a Yew app. Each Component
/// chooses how to display itself using received props and self-managed state.
/// Components can be dynamic and interactive by declaring messages that are
/// triggered and handled asynchronously. This async update mechanism is inspired by
/// Elm and the actor model used in the Actix framework.
pub trait Component: Sized + 'static {
/// Control message type which `update` loop get.
/// Messages are used to make Components dynamic and interactive. Simple
/// Component's can declare their Message type to be `()`. Complex Component's
/// commonly use an enum to declare multiple Message types.
type Message: 'static;
/// Properties type of component implementation.

/// Properties are the inputs to a Component and should not mutated within a
/// Component. They are passed to a Component using a JSX-style syntax.
/// ```
///# use yew::{Html, Component, Properties, ComponentLink, html};
///# struct Model;
///# #[derive(Clone, Properties)]
///# struct Props {
///# prop: String,
///# }
///# impl Component for Model {
///# type Message = ();type Properties = Props;
///# fn create(props: Self::Properties,link: ComponentLink<Self>) -> Self {unimplemented!()}
///# fn update(&mut self,msg: Self::Message) -> bool {unimplemented!()}
///# fn change(&mut self, _: Self::Properties) -> bool {unimplemented!()}
///# fn view(&self) -> Html {
/// html! {
/// <Model prop="value" />
/// }
///# }}
/// ```
type Properties: Properties;
/// Initialization routine which could use a context.

/// Components are created with their properties as well as a `ComponentLink` which
/// can be used to send messages and create callbacks for triggering updates.
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self;
/// Called after the component has been attached to the VDOM and it is safe to receive messages
/// from agents but before the browser updates the screen. If true is returned, the view will
Expand All @@ -48,15 +76,36 @@ pub trait Component: Sized + 'static {
/// Called everytime when a messages of `Msg` type received. It also takes a
/// reference to a context.
fn update(&mut self, msg: Self::Message) -> ShouldRender;
/// Called when the component's parent component re-renders and the
/// component's place in the DOM tree remains unchanged. If the component's
/// place in the DOM tree changes, calling this method is unnecessary as the
/// component is recreated from scratch. It defaults to true if not implemented
/// and Self::Properties is not the unit type `()`.
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
TypeId::of::<Self::Properties>() != TypeId::of::<()>()
}
/// Called by rendering loop.

/// When the parent of a Component is re-rendered, it will either be re-created or
/// receive new properties in the `change` lifecycle method. Component's can choose
/// to re-render if the new properties are different than the previously
/// received properties. Most Component's will use props with a `PartialEq`
/// impl and will be implemented like this:
/// ```
///# use yew::{Html, Component, ComponentLink, html, ShouldRender};
///# struct Model{props: ()};
///# impl Component for Model {
///# type Message = ();type Properties = ();
///# fn create(props: Self::Properties,link: ComponentLink<Self>) -> Self {unimplemented!()}
///# fn update(&mut self,msg: Self::Message) -> bool {unimplemented!()}
///# fn view(&self) -> Html {unimplemented!()}
/// fn change(&mut self, props: Self::Properties) -> ShouldRender {
/// if self.props != props {
/// self.props = props;
/// true
/// } else {
/// false
/// }
/// }
///# }
/// ```
/// Components which don't have properties should always return false.
fn change(&mut self, _props: Self::Properties) -> ShouldRender;

/// Components define their visual layout using a JSX-style syntax through the use of the
/// `html!` procedural macro. The full guide to using the macro can be found in [Yew's
/// documentation](https://yew.rs/docs/concepts/html).
fn view(&self) -> Html;
/// Called for finalization on the final point of the component's lifetime.
fn destroy(&mut self) {} // TODO(#941): Replace with `Drop`
Expand All @@ -83,6 +132,7 @@ pub type Html = VNode;
///# type Properties = WrapperProps;
///# fn create(props: Self::Properties,link: ComponentLink<Self>) -> Self {unimplemented!()}
///# fn update(&mut self,msg: Self::Message) -> bool {unimplemented!()}
///# fn change(&mut self, _: Self::Properties) -> bool {unimplemented!()}
///# // This is not a valid implementation. This is done for space convenience.
///# fn view(&self) -> Html {
/// html! {
Expand Down Expand Up @@ -113,6 +163,7 @@ pub type Html = VNode;
///# type Properties = WrapperProps;
///# fn create(props: Self::Properties,link: ComponentLink<Self>) -> Self {unimplemented!()}
///# fn update(&mut self,msg: Self::Message) -> bool {unimplemented!()}
///# fn change(&mut self, _: Self::Properties) -> bool {unimplemented!()}
/// fn view(&self) -> Html {
/// html! {
/// <div id="container">
Expand Down Expand Up @@ -143,6 +194,7 @@ pub type Children = ChildrenRenderer<Html>;
///# type Properties = ListProps;
///# fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {unimplemented!()}
///# fn update(&mut self, msg: Self::Message) -> bool {unimplemented!()}
///# fn change(&mut self, _: Self::Properties) -> bool {unimplemented!()}
///# fn view(&self) -> Html {unimplemented!()}
///# }
///# #[derive(Clone, Properties)]
Expand All @@ -155,6 +207,7 @@ pub type Children = ChildrenRenderer<Html>;
///# type Properties = ListItemProps;
///# fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {unimplemented!()}
///# fn update(&mut self, msg: Self::Message) -> bool {unimplemented!()}
///# fn change(&mut self, _: Self::Properties) -> bool {unimplemented!()}
///# fn view(&self) -> Html {unimplemented!()}
///# }
///# fn view() -> Html {
Expand Down Expand Up @@ -186,6 +239,7 @@ pub type Children = ChildrenRenderer<Html>;
///# type Properties = ListProps;
///# fn create(props: Self::Properties,link: ComponentLink<Self>) -> Self {unimplemented!()}
///# fn update(&mut self,msg: Self::Message) -> bool {unimplemented!()}
///# fn change(&mut self, _: Self::Properties) -> bool {unimplemented!()}
/// // ...
/// fn view(&self) -> Html {
/// html!{{
Expand All @@ -209,6 +263,7 @@ pub type Children = ChildrenRenderer<Html>;
///# type Properties = ListItemProps;
///# fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {unimplemented!()}
///# fn update(&mut self, msg: Self::Message) -> bool {unimplemented!()}
///# fn change(&mut self, _: Self::Properties) -> bool {unimplemented!()}
///# fn view(&self) -> Html {unimplemented!()}
///# }
/// ```
Expand Down Expand Up @@ -308,6 +363,9 @@ where
/// if let Some(input) = self.node_ref.cast::<InputElement>() {
/// input.focus();
/// }
/// }
///
/// fn change(&mut self, _: Self::Properties) -> ShouldRender {
/// false
/// }
///
Expand Down
4 changes: 4 additions & 0 deletions src/lib.rs
Expand Up @@ -51,6 +51,10 @@
//! true
//! }
//!
//! fn change(&mut self, _: Self::Properties) -> ShouldRender {
//! false
//! }
//!
//! fn view(&self) -> Html {
//! html! {
//! <div>
Expand Down
5 changes: 4 additions & 1 deletion src/services/fetch/std_web.rs
Expand Up @@ -185,7 +185,7 @@ impl FetchService {
/// .expect("Failed to build request.");
/// ```
///
/// The callback function can build a loop message by passing or analizing the
/// The callback function can build a loop message by passing or analyzing the
/// response body and metadata.
///
/// ```
Expand All @@ -197,6 +197,7 @@ impl FetchService {
///# type Message = Msg;type Properties = ();
///# fn create(props: Self::Properties,link: ComponentLink<Self>) -> Self {unimplemented!()}
///# fn update(&mut self,msg: Self::Message) -> bool {unimplemented!()}
///# fn change(&mut self, _: Self::Properties) -> bool {unimplemented!()}
///# fn view(&self) -> Html {unimplemented!()}
///# }
///# enum Msg {
Expand Down Expand Up @@ -236,6 +237,7 @@ impl FetchService {
///# type Message = Msg;type Properties = ();
///# fn create(props: Self::Properties,link: ComponentLink<Self>) -> Self {unimplemented!()}
///# fn update(&mut self,msg: Self::Message) -> bool {unimplemented!()}
///# fn change(&mut self, _: Self::Properties) -> bool {unimplemented!()}
///# fn view(&self) -> Html {unimplemented!()}
///# }
///# enum Msg {
Expand Down Expand Up @@ -289,6 +291,7 @@ impl FetchService {
///# type Properties = ();
///# fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {unimplemented!()}
///# fn update(&mut self, msg: Self::Message) -> bool {unimplemented!()}
///# fn change(&mut self, _: Self::Properties) -> bool {unimplemented!()}
///# fn view(&self) -> Html {unimplemented!()}
///# }
///# pub enum Msg { }
Expand Down
3 changes: 3 additions & 0 deletions src/services/fetch/web_sys.rs
Expand Up @@ -199,6 +199,7 @@ impl FetchService {
///# type Message = Msg;type Properties = ();
///# fn create(props: Self::Properties,link: ComponentLink<Self>) -> Self {unimplemented!()}
///# fn update(&mut self,msg: Self::Message) -> bool {unimplemented!()}
///# fn change(&mut self, _: Self::Properties) -> bool {unimplemented!()}
///# fn view(&self) -> Html {unimplemented!()}
///# }
///# enum Msg {
Expand Down Expand Up @@ -239,6 +240,7 @@ impl FetchService {
///# type Message = Msg;type Properties = ();
///# fn create(props: Self::Properties,link: ComponentLink<Self>) -> Self {unimplemented!()}
///# fn update(&mut self,msg: Self::Message) -> bool {unimplemented!()}
///# fn change(&mut self, _: Self::Properties) -> bool {unimplemented!()}
///# fn view(&self) -> Html {unimplemented!()}
///# }
///# enum Msg {
Expand Down Expand Up @@ -293,6 +295,7 @@ impl FetchService {
///# type Properties = ();
///# fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {unimplemented!()}
///# fn update(&mut self, msg: Self::Message) -> bool {unimplemented!()}
///# fn change(&mut self, _: Self::Properties) -> bool {unimplemented!()}
///# fn view(&self) -> Html {unimplemented!()}
///# }
///# pub enum Msg {}
Expand Down
4 changes: 4 additions & 0 deletions src/virtual_dom/vcomp.rs
Expand Up @@ -346,6 +346,10 @@ mod tests {
unimplemented!();
}

fn change(&mut self, _: Self::Properties) -> ShouldRender {
unimplemented!();
}

fn view(&self) -> Html {
unimplemented!();
}
Expand Down
4 changes: 4 additions & 0 deletions src/virtual_dom/vlist.rs
Expand Up @@ -146,6 +146,10 @@ mod tests {
unimplemented!();
}

fn change(&mut self, _: Self::Properties) -> ShouldRender {
unimplemented!();
}

fn view(&self) -> Html {
unimplemented!();
}
Expand Down
12 changes: 12 additions & 0 deletions src/virtual_dom/vtag.rs
Expand Up @@ -575,6 +575,10 @@ mod tests {
unimplemented!();
}

fn change(&mut self, _: Self::Properties) -> ShouldRender {
unimplemented!();
}

fn view(&self) -> Html {
unimplemented!();
}
Expand All @@ -594,6 +598,10 @@ mod tests {
unimplemented!();
}

fn change(&mut self, _: Self::Properties) -> ShouldRender {
unimplemented!();
}

fn view(&self) -> Html {
unimplemented!();
}
Expand All @@ -613,6 +621,10 @@ mod tests {
unimplemented!();
}

fn change(&mut self, _: Self::Properties) -> ShouldRender {
unimplemented!();
}

fn view(&self) -> Html {
unimplemented!();
}
Expand Down
4 changes: 4 additions & 0 deletions src/virtual_dom/vtext.rs
Expand Up @@ -148,6 +148,10 @@ mod test {
unimplemented!();
}

fn change(&mut self, _: Self::Properties) -> ShouldRender {
unimplemented!();
}

fn view(&self) -> Html {
unimplemented!();
}
Expand Down

0 comments on commit 60e5ab2

Please sign in to comment.