From c7100a7a45a4dcc19323f1837fc745a4ae4af0f3 Mon Sep 17 00:00:00 2001 From: Richard LASJUNIES Date: Fri, 8 May 2020 17:44:56 +0200 Subject: [PATCH 1/7] Comp readme update + add life cyle page --- src/SUMMARY.md | 1 + src/concepts/components/README.md | 173 ++++----------------------- src/concepts/components/lifecycle.md | 167 ++++++++++++++++++++++++++ src/lib.rs | 5 + 4 files changed, 196 insertions(+), 150 deletions(-) create mode 100644 src/concepts/components/lifecycle.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 99f9c4e..0ccb537 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -24,6 +24,7 @@ * [Properties](concepts/components/properties.md) * [Callbacks](concepts/components/callbacks.md) * [Refs](concepts/components/refs.md) + * [Life cyle](concepts/components/lifecycle.md) * [Agents](concepts/agents.md) * [Services](concepts/services/README.md) * [Format](concepts/services/format.md) diff --git a/src/concepts/components/README.md b/src/concepts/components/README.md index aa8adb3..0e72b39 100644 --- a/src/concepts/components/README.md +++ b/src/concepts/components/README.md @@ -4,175 +4,48 @@ description: Components and their lifecycle hooks # Components -## What are Components? +## What are Components Components are the building blocks of Yew. They manage their own state and can render themselves to the DOM. Components are created by implementing the `Component` trait which describes the lifecycle of a component. -## Lifecycle - -{% hint style="info" %} -`Contribute to our docs:` [Add a diagram of the component lifecycle](https://github.com/yewstack/docs/issues/22) -{% endhint %} - -## Lifecycle Methods - -### Create - -When a component is created, it receives properties from its parent component as well as a `ComponentLink`. The properties can be used to initialize the component's state and the "link" can be used to register callbacks or send messages to the component. - -It is common to store the props and the link in your component struct, like so: - -```rust -pub struct MyComponent { - props: Props, - link: ComponentLink, -} - -impl Component for MyComponent { - type Properties = Props; - // ... - - fn create(props: Self::Properties, link: ComponentLink) -> Self { - MyComponent { props, link } - } - - // ... -} -``` - -### View - -Components declare their layout in the `view()` method. Yew provides the `html!` macro for declaring HTML and SVG nodes and their listeners as well as child components. The macro acts a lot like React's JSX, but uses Rust expressions instead of JavaScript. - -```rust -impl Component for MyComponent { - // ... - - fn view(&self) -> Html { - let onclick = self.link.callback(|_| Msg::Click); - html! { - - } - } -} -``` - -For usage details, check out the `html!` guide: - -{% page-ref page="../html/" %} - -### Rendered - -The `rendered()` component lifecycle method is called after `view()` is processed and Yew has rendered your component, but before the browser refreshes the page. A component may wish to implement this method to perform actions that can only be done after the component has rendered elements. You can check whether this is the first time the component was rendered via the `first_render` parameter. +## Simple Component ```rust -use stdweb::web::html_element::InputElement; -use stdweb::web::IHtmlElement; use yew::prelude::*; +pub struct SimpleComponent {} -pub struct MyComponent { - node_ref: NodeRef, -} - -impl Component for MyComponent { - // ... +impl Component for SimpleComponent { + type Message = (); + type Properties = (); - fn view(&self) -> Html { - html! { - - } + fn create(_props: Self::Properties, _link: ComponentLink) -> Self { + Self {} } - fn rendered(&mut self, first_render: bool) { - if first_render { - if let Some(input) = self.node_ref.try_into::() { - input.focus(); - } - } + fn update(&mut self, _msg: Self::Message) -> ShouldRender { + true } -} -``` - -{% hint style="info" %} -Note that this lifecycle method does not require an implementation and will do nothing by default -{% endhint %} - -### Update -Components are dynamic and can register to receive asynchronous messages. The `update()` lifecycle method is called for each message. This allows the component to update itself based on what the message was, and determine if it needs to re-render itself. Messages can be triggered by HTML elements listeners or be sent by child components, Agents, Services, or Futures. - -Here's an example of what `update()` could look like: - -```rust -pub enum Msg { - SetInputEnabled(bool) -} - -impl Component for MyComponent { - type Message = Msg; - - // ... - - fn update(&mut self, msg: Self::Message) -> ShouldRender { - match msg { - Msg::SetInputEnabled(enabled) => { - if self.input_enabled != enabled { - self.input_enabled = enabled; - true // Re-render - } else { - false - } - } - } + fn change(&mut self, _props: Self::Properties) -> ShouldRender { + true } -} -``` - -### Change - -Components may be re-rendered by their parents. When this happens, they could receive new properties and choose to re-render. This design facilitates parent to child component communication through changed properties. - -A typical implementation would look like: -```rust -impl Component for MyComponent { - // ... - - fn change(&mut self, props: Self::Properties) -> ShouldRender { - if self.props != props { - self.props = props; - true - } else { - false + fn view(&self) -> Html { + html! { + <> +

{"Hello World!"}

+ } } } ``` -### Destroy - -After Components are unmounted from the DOM, Yew calls the `destroy()` lifecycle method to support any necessary clean up operations. This method is optional and does nothing by default. - -## Associated Types - -The `Component` trait has two associated types: `Message` and `Properties`. - -```rust -impl Component for MyComponent { - type Message = Msg; - type Properties = Props; - - // ... -} -``` +> one think to highlight here, is how to render the message. As explained in the `html!` macro doumentation, the literals must be quoted and curly braced: `{"Hello World!"}` -`Message` represents a variety of messages that can be processed by the component to trigger some side effect. For example, you may have a `Click` message which triggers an API request or toggles the appearance of a UI component. It is common practice to create an enum called `Msg` in your component's module and use that as the message type in the component. It is common to shorten "message" to "msg". +This component could be invoked in your page like this: -```rust -enum Msg { - Click, -} +```html + ... + + ... ``` - -`Properties` represents the information passed to a component from its parent. This type must implements the `Properties` trait \(usually by deriving it\) and can specify whether certain properties are required or optional. This type is used when creating and updating a component. It is common practice to create a struct called `Props` in your component's module and use that as the component's `Properties` type. It is common to shorten "properties" to "props". Since props are handed down from parent components, the root component of your application typically has a `Properties` type of `()`. If you wish to specify properties for your root component, use the `App::mount_with_props` method. - diff --git a/src/concepts/components/lifecycle.md b/src/concepts/components/lifecycle.md new file mode 100644 index 0000000..7051417 --- /dev/null +++ b/src/concepts/components/lifecycle.md @@ -0,0 +1,167 @@ +--- +description: Component life cycle +--- + +# Life cycle + +{% hint style="info" %} +`Contribute to our docs:` [Add a diagram of the component lifecycle](https://github.com/yewstack/docs/issues/22) +{% endhint %} + +## Lifecycle Methods + +### Create + +When a component is created, it receives properties from its parent component as well as a `ComponentLink`. The properties can be used to initialize the component's state and the "link" can be used to register callbacks or send messages to the component. + +It is common to store the props and the link in your component struct, like so: + +```rust +pub struct MyComponent { + props: Props, + link: ComponentLink, +} + +impl Component for MyComponent { + type Properties = Props; + // ... + + fn create(props: Self::Properties, link: ComponentLink) -> Self { + MyComponent { props, link } + } + + // ... +} +``` + +### View + +Components declare their layout in the `view()` method. Yew provides the `html!` macro for declaring HTML and SVG nodes and their listeners as well as child components. The macro acts a lot like React's JSX, but uses Rust expressions instead of JavaScript. + +```rust +impl Component for MyComponent { + // ... + + fn view(&self) -> Html { + let onclick = self.link.callback(|_| Msg::Click); + html! { + + } + } +} +``` + +For usage details, check out the `html!` guide: + +{% page-ref page="../html/" %} + +### Rendered + +The `rendered()` component lifecycle method is called after `view()` is processed and Yew has rendered your component, but before the browser refreshes the page. A component may wish to implement this method to perform actions that can only be done after the component has rendered elements. You can check whether this is the first time the component was rendered via the `first_render` parameter. + +```rust +use stdweb::web::html_element::InputElement; +use stdweb::web::IHtmlElement; +use yew::prelude::*; + +pub struct MyComponent { + node_ref: NodeRef, +} + +impl Component for MyComponent { + // ... + + fn view(&self) -> Html { + html! { + + } + } + + fn rendered(&mut self, first_render: bool) { + if first_render { + if let Some(input) = self.node_ref.try_into::() { + input.focus(); + } + } + } +} +``` + +{% hint style="info" %} +Note that this lifecycle method does not require an implementation and will do nothing by default +{% endhint %} + +### Update + +Components are dynamic and can register to receive asynchronous messages. The `update()` lifecycle method is called for each message. This allows the component to update itself based on what the message was, and determine if it needs to re-render itself. Messages can be triggered by HTML elements listeners or be sent by child components, Agents, Services, or Futures. + +Here's an example of what `update()` could look like: + +```rust +pub enum Msg { + SetInputEnabled(bool) +} + +impl Component for MyComponent { + type Message = Msg; + + // ... + + fn update(&mut self, msg: Self::Message) -> ShouldRender { + match msg { + Msg::SetInputEnabled(enabled) => { + if self.input_enabled != enabled { + self.input_enabled = enabled; + true // Re-render + } else { + false + } + } + } + } +} +``` + +### Change + +Components may be re-rendered by their parents. When this happens, they could receive new properties and choose to re-render. This design facilitates parent to child component communication through changed properties. You don't have to implement `change()` but you probably want to if you want to update a component via props after it has been created. + +A naive implementation would look like: + +```rust +impl Component for MyComponent { + // ... + + fn change(&mut self, props: Self::Properties) -> ShouldRender { + self.props = props; + true // This will always re-render when new props are provided. + } +} +``` + +### Destroy + +After Components are unmounted from the DOM, Yew calls the `destroy()` lifecycle method to support any necessary clean up operations. This method is optional and does nothing by default. + +## Associated Types + +The `Component` trait has two associated types: `Message` and `Properties`. + +```rust +impl Component for MyComponent { + type Message = Msg; + type Properties = Props; + + // ... +} +``` + +`Message` represents a variety of messages that can be processed by the component to trigger some side effect. For example, you may have a `Click` message which triggers an API request or toggles the appearance of a UI component. It is common practice to create an enum called `Msg` in your component's module and use that as the message type in the component. It is common to shorten "message" to "msg". + +```rust +enum Msg { + Click, +} +``` + +`Properties` represents the information passed to a component from its parent. This type must implements the `Properties` trait \(usually by deriving it\) and can specify whether certain properties are required or optional. This type is used when creating and updating a component. It is common practice to create a struct called `Props` in your component's module and use that as the component's `Properties` type. It is common to shorten "properties" to "props". Since props are handed down from parent components, the root component of your application typically has a `Properties` type of `()`. If you wish to specify properties for your root component, use the `App::mount_with_props` method. diff --git a/src/lib.rs b/src/lib.rs index 69b0734..d8a897d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,3 +18,8 @@ fn test_optimizations() { fn test_properties() { doctest!("concepts/components/properties.md"); } + +#[wasm_bindgen_test] +fn test_component_readme() { + doctest!("concepts/components/readme.md"); +} \ No newline at end of file From f8c159e0bdc69301c61391b6b5c766e83e5b8bf4 Mon Sep 17 00:00:00 2001 From: Richard LASJUNIES Date: Fri, 8 May 2020 17:56:20 +0200 Subject: [PATCH 2/7] add internalstate page --- src/SUMMARY.md | 1 + src/concepts/components/internalstate.md | 168 +++++++++++++++++++++++ src/lib.rs | 5 + 3 files changed, 174 insertions(+) create mode 100644 src/concepts/components/internalstate.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 0ccb537..e1785d2 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -21,6 +21,7 @@ * [Literals & Expressions](concepts/html/literals-and-expressions.md) * [Components](concepts/html/components.md) * [Components](concepts/components/README.md) + * [Internal state](concepts/components/internalstate.md) * [Properties](concepts/components/properties.md) * [Callbacks](concepts/components/callbacks.md) * [Refs](concepts/components/refs.md) diff --git a/src/concepts/components/internalstate.md b/src/concepts/components/internalstate.md new file mode 100644 index 0000000..408a790 --- /dev/null +++ b/src/concepts/components/internalstate.md @@ -0,0 +1,168 @@ +--- +description: Component can maintain it's own state and render information depending on it +--- + +# Internal State + +The component can manage it's own state withing Rust struct. The rendering is done based on the state and it's mutation. + +> **TODO a chapter state mutation** + +```rust +use yew::prelude::*; + +pub struct InternalStateComponent { + name:String, +} + +impl Component for InternalStateComponent { + type Message = (); + type Properties = (); + + fn create(_props: Self::Properties, _link: ComponentLink) -> Self { + Self { + name: "Clark".into(), + } + } + + fn update(&mut self, _msg: Self::Message) -> ShouldRender { + true + } + + fn change(&mut self, _props: Self::Properties) -> ShouldRender { + true + } + + fn view(&self) -> Html { + html! { + <> +

{format!("Hello {}",self.name)}

+ + } + } +} +``` + +## State definition + +Here we add the `name` field in the struct + +```rust +# use yew::prelude::*; +# +// ... +pub struct InternalStateComponent { + name:String, +} +// ... +# +# impl Component for InternalStateComponent { +# type Message = (); +# type Properties = (); +# +# fn create(_props: Self::Properties, _link: ComponentLink) -> Self { +# Self { +# name: "Clark".into(), +# } +# } +# +# fn update(&mut self, _msg: Self::Message) -> ShouldRender { +# true +# } +# +# fn change(&mut self, _props: Self::Properties) -> ShouldRender { +# true +# } +# +# fn view(&self) -> Html { +# html! { +# <> +#

{format!("Hello {}",self.name)}

+# +# } +# } +# } + +``` + +## State initialization + +The component lifecycle will initialize the state in the `create` method. + +```rust +# use yew::prelude::*; +# +# pub struct InternalStateComponent { +# name:String, +# } +# +# impl Component for InternalStateComponent { +# type Message = (); +# type Properties = (); +// ... + fn create(_props: Self::Properties, _link: ComponentLink) -> Self { + Self { + name: "Clark".into(), + } + } +// ... +# fn update(&mut self, _msg: Self::Message) -> ShouldRender { +# true +# } +# +# fn change(&mut self, _props: Self::Properties) -> ShouldRender { +# true +# } +# +# fn view(&self) -> Html { +# html! { +# <> +#

{format!("Hello {}",self.name)}

+# +# } +# } +# } +``` + +## Rendering based on the state value + +Using the `html!` macro we can render html based on the component state in the `view` method + +> please refer to the `html!` macro documentation page for more detail on the HTML rendering + +```rust +# use yew::prelude::*; +# +# pub struct InternalStateComponent { +# name:String, +# } +# +# impl Component for InternalStateComponent { +# type Message = (); +# type Properties = (); +# +# fn create(_props: Self::Properties, _link: ComponentLink) -> Self { +# Self { +# name: "Clark".into(), +# } +# } +# +# fn update(&mut self, _msg: Self::Message) -> ShouldRender { +# true +# } +# +# fn change(&mut self, _props: Self::Properties) -> ShouldRender { +# true +# } +# +// ... + fn view(&self) -> Html { + html! { + <> +

{format!("Hello {}",self.name)}

+ + } + } +// ... +# } +``` diff --git a/src/lib.rs b/src/lib.rs index d8a897d..46e34ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,4 +22,9 @@ fn test_properties() { #[wasm_bindgen_test] fn test_component_readme() { doctest!("concepts/components/readme.md"); +} + +#[wasm_bindgen_test] +fn test_component_internalstate() { + doctest!("concepts/components/internalstate.md"); } \ No newline at end of file From 6fc6256c7d608cc6352d8ffe02176cd9cfa9c4da Mon Sep 17 00:00:00 2001 From: Richard LASJUNIES Date: Fri, 8 May 2020 17:58:41 +0200 Subject: [PATCH 3/7] Revert "add internalstate page" This reverts commit f8c159e0bdc69301c61391b6b5c766e83e5b8bf4. --- src/SUMMARY.md | 1 - src/concepts/components/internalstate.md | 168 ----------------------- src/lib.rs | 5 - 3 files changed, 174 deletions(-) delete mode 100644 src/concepts/components/internalstate.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index e1785d2..0ccb537 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -21,7 +21,6 @@ * [Literals & Expressions](concepts/html/literals-and-expressions.md) * [Components](concepts/html/components.md) * [Components](concepts/components/README.md) - * [Internal state](concepts/components/internalstate.md) * [Properties](concepts/components/properties.md) * [Callbacks](concepts/components/callbacks.md) * [Refs](concepts/components/refs.md) diff --git a/src/concepts/components/internalstate.md b/src/concepts/components/internalstate.md deleted file mode 100644 index 408a790..0000000 --- a/src/concepts/components/internalstate.md +++ /dev/null @@ -1,168 +0,0 @@ ---- -description: Component can maintain it's own state and render information depending on it ---- - -# Internal State - -The component can manage it's own state withing Rust struct. The rendering is done based on the state and it's mutation. - -> **TODO a chapter state mutation** - -```rust -use yew::prelude::*; - -pub struct InternalStateComponent { - name:String, -} - -impl Component for InternalStateComponent { - type Message = (); - type Properties = (); - - fn create(_props: Self::Properties, _link: ComponentLink) -> Self { - Self { - name: "Clark".into(), - } - } - - fn update(&mut self, _msg: Self::Message) -> ShouldRender { - true - } - - fn change(&mut self, _props: Self::Properties) -> ShouldRender { - true - } - - fn view(&self) -> Html { - html! { - <> -

{format!("Hello {}",self.name)}

- - } - } -} -``` - -## State definition - -Here we add the `name` field in the struct - -```rust -# use yew::prelude::*; -# -// ... -pub struct InternalStateComponent { - name:String, -} -// ... -# -# impl Component for InternalStateComponent { -# type Message = (); -# type Properties = (); -# -# fn create(_props: Self::Properties, _link: ComponentLink) -> Self { -# Self { -# name: "Clark".into(), -# } -# } -# -# fn update(&mut self, _msg: Self::Message) -> ShouldRender { -# true -# } -# -# fn change(&mut self, _props: Self::Properties) -> ShouldRender { -# true -# } -# -# fn view(&self) -> Html { -# html! { -# <> -#

{format!("Hello {}",self.name)}

-# -# } -# } -# } - -``` - -## State initialization - -The component lifecycle will initialize the state in the `create` method. - -```rust -# use yew::prelude::*; -# -# pub struct InternalStateComponent { -# name:String, -# } -# -# impl Component for InternalStateComponent { -# type Message = (); -# type Properties = (); -// ... - fn create(_props: Self::Properties, _link: ComponentLink) -> Self { - Self { - name: "Clark".into(), - } - } -// ... -# fn update(&mut self, _msg: Self::Message) -> ShouldRender { -# true -# } -# -# fn change(&mut self, _props: Self::Properties) -> ShouldRender { -# true -# } -# -# fn view(&self) -> Html { -# html! { -# <> -#

{format!("Hello {}",self.name)}

-# -# } -# } -# } -``` - -## Rendering based on the state value - -Using the `html!` macro we can render html based on the component state in the `view` method - -> please refer to the `html!` macro documentation page for more detail on the HTML rendering - -```rust -# use yew::prelude::*; -# -# pub struct InternalStateComponent { -# name:String, -# } -# -# impl Component for InternalStateComponent { -# type Message = (); -# type Properties = (); -# -# fn create(_props: Self::Properties, _link: ComponentLink) -> Self { -# Self { -# name: "Clark".into(), -# } -# } -# -# fn update(&mut self, _msg: Self::Message) -> ShouldRender { -# true -# } -# -# fn change(&mut self, _props: Self::Properties) -> ShouldRender { -# true -# } -# -// ... - fn view(&self) -> Html { - html! { - <> -

{format!("Hello {}",self.name)}

- - } - } -// ... -# } -``` diff --git a/src/lib.rs b/src/lib.rs index 46e34ab..d8a897d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,9 +22,4 @@ fn test_properties() { #[wasm_bindgen_test] fn test_component_readme() { doctest!("concepts/components/readme.md"); -} - -#[wasm_bindgen_test] -fn test_component_internalstate() { - doctest!("concepts/components/internalstate.md"); } \ No newline at end of file From 836a92be543cf20ccb01f0f7e20fec6fc0e1eb4e Mon Sep 17 00:00:00 2001 From: Richard LASJUNIES Date: Fri, 8 May 2020 18:12:01 +0200 Subject: [PATCH 4/7] add internal state page --- src/SUMMARY.md | 1 + src/concepts/components/internalstate.md | 169 +++++++++++++++++++++++ src/lib.rs | 5 + 3 files changed, 175 insertions(+) create mode 100644 src/concepts/components/internalstate.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 0ccb537..e1785d2 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -21,6 +21,7 @@ * [Literals & Expressions](concepts/html/literals-and-expressions.md) * [Components](concepts/html/components.md) * [Components](concepts/components/README.md) + * [Internal state](concepts/components/internalstate.md) * [Properties](concepts/components/properties.md) * [Callbacks](concepts/components/callbacks.md) * [Refs](concepts/components/refs.md) diff --git a/src/concepts/components/internalstate.md b/src/concepts/components/internalstate.md new file mode 100644 index 0000000..0e4b674 --- /dev/null +++ b/src/concepts/components/internalstate.md @@ -0,0 +1,169 @@ +--- +description: Component can maintain it's own state and render information depending on it +--- + +# Internal State + +The component can manage it's own state using the Rust struct that implement the trait `Component`. The HTML rendering is based on this state. +When state change there is possibility to re-render the component. + +> TODO documentation on state mutation + +```rust +use yew::prelude::*; + +pub struct InternalStateComponent { + name:String, +} + +impl Component for InternalStateComponent { + type Message = (); + type Properties = (); + + fn create(_props: Self::Properties, _link: ComponentLink) -> Self { + Self { + name: "Clark".into(), + } + } + + fn update(&mut self, _msg: Self::Message) -> ShouldRender { + true + } + + fn change(&mut self, _props: Self::Properties) -> ShouldRender { + true + } + + fn view(&self) -> Html { + html! { + <> +

{format!("Hello {}",self.name)}

+ + } + } +} +``` + +## State definition + +Here we add the `name` field in the struct + +```rust +# use yew::prelude::*; +# +// ... +pub struct InternalStateComponent { + name:String, +} +// ... +# +# impl Component for InternalStateComponent { +# type Message = (); +# type Properties = (); +# +# fn create(_props: Self::Properties, _link: ComponentLink) -> Self { +# Self { +# name: "Clark".into(), +# } +# } +# +# fn update(&mut self, _msg: Self::Message) -> ShouldRender { +# true +# } +# +# fn change(&mut self, _props: Self::Properties) -> ShouldRender { +# true +# } +# +# fn view(&self) -> Html { +# html! { +# <> +#

{format!("Hello {}",self.name)}

+# +# } +# } +# } + +``` + +## State initialization + +The component lifecycle will initialize the state in the `create` method. + +```rust +# use yew::prelude::*; +# +# pub struct InternalStateComponent { +# name:String, +# } +# +# impl Component for InternalStateComponent { +# type Message = (); +# type Properties = (); +// ... + fn create(_props: Self::Properties, _link: ComponentLink) -> Self { + Self { + name: "Clark".into(), + } + } +// ... +# fn update(&mut self, _msg: Self::Message) -> ShouldRender { +# true +# } +# +# fn change(&mut self, _props: Self::Properties) -> ShouldRender { +# true +# } +# +# fn view(&self) -> Html { +# html! { +# <> +#

{format!("Hello {}",self.name)}

+# +# } +# } +# } +``` + +## Rendering based on the state value + +Using the `html!` macro we can render html based on the component state in the `view` method + +> please refer to the `html!` macro documentation page for more detail on the HTML rendering + +```rust +# use yew::prelude::*; +# +# pub struct InternalStateComponent { +# name:String, +# } +# +# impl Component for InternalStateComponent { +# type Message = (); +# type Properties = (); +# +# fn create(_props: Self::Properties, _link: ComponentLink) -> Self { +# Self { +# name: "Clark".into(), +# } +# } +# +# fn update(&mut self, _msg: Self::Message) -> ShouldRender { +# true +# } +# +# fn change(&mut self, _props: Self::Properties) -> ShouldRender { +# true +# } +# +// ... + fn view(&self) -> Html { + html! { + <> +

{format!("Hello {}",self.name)}

+ + } + } +// ... +# } +``` diff --git a/src/lib.rs b/src/lib.rs index d8a897d..46e34ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,4 +22,9 @@ fn test_properties() { #[wasm_bindgen_test] fn test_component_readme() { doctest!("concepts/components/readme.md"); +} + +#[wasm_bindgen_test] +fn test_component_internalstate() { + doctest!("concepts/components/internalstate.md"); } \ No newline at end of file From 3cc8641398010e391e8b2cad05dc60c341b79e99 Mon Sep 17 00:00:00 2001 From: Richard LASJUNIES Date: Fri, 8 May 2020 20:21:41 +0200 Subject: [PATCH 5/7] Replace SimpleComponent by ExampleComponent --- src/concepts/components/README.md | 94 +++++++++++++++++++++++-------- 1 file changed, 69 insertions(+), 25 deletions(-) diff --git a/src/concepts/components/README.md b/src/concepts/components/README.md index 0e72b39..f8da63f 100644 --- a/src/concepts/components/README.md +++ b/src/concepts/components/README.md @@ -8,44 +8,88 @@ description: Components and their lifecycle hooks Components are the building blocks of Yew. They manage their own state and can render themselves to the DOM. Components are created by implementing the `Component` trait which describes the lifecycle of a component. -## Simple Component +## Example of component ```rust use yew::prelude::*; -pub struct SimpleComponent {} -impl Component for SimpleComponent { - type Message = (); - type Properties = (); +pub struct ExampleComponent { + // state of the component + name: String, + show_message: bool, - fn create(_props: Self::Properties, _link: ComponentLink) -> Self { - Self {} + // properties and events bag + props: Props, + + // link field supports the mechanism through which components are able to register callbacks and update themselves + link: ComponentLink, +} + +// enum of "Messages" that will be used to mutate the component state +pub enum Msg { + Click(), +} + +// definition of properties and events of the component +#[derive(Properties, Clone, PartialEq)] +pub struct Props{ + #[prop_or("Superman".to_string())] + pub name: String, + + #[prop_or_default] + pub onmyclickevent:Callback, +} + +impl Component for ExampleComponent { + type Message = Msg; + type Properties = Props; + + // Initialization of the state + fn create(props: Self::Properties, link: ComponentLink) -> Self { + Self { + link, + props: props.clone(), + name: props.name.into(), + show_message: false, + } } - fn update(&mut self, _msg: Self::Message) -> ShouldRender { + // This method is executed each time the link.callbacks is called + // you can mutate the state based on the message received + fn update(&mut self, msg: Self::Message) -> ShouldRender { + match msg { + + // mutate the component state + Msg::Click() => self.show_message = true, + } true } - fn change(&mut self, _props: Self::Properties) -> ShouldRender { - true + // mutate state if the properties bag is changed + fn change(&mut self, props: Self::Properties) -> ShouldRender { + if self.props != props { + self.props = props; + true + } else { + false + } } + // Rendering of the component + // The method is called when 'ShouldRender' is 'true' as return of update and change method fn view(&self) -> Html { - html! { - <> -

{"Hello World!"}

- + // different rendering depend on the component state + if !self.show_message { + html! { + // trap HTML events and trigger a message that will be managed in the update method + + } + } else { + html! { + // Use state value in the html +

{format!("Hello {}",self.name)}

+ } } } } -``` - -> one think to highlight here, is how to render the message. As explained in the `html!` macro doumentation, the literals must be quoted and curly braced: `{"Hello World!"}` - -This component could be invoked in your page like this: - -```html - ... - - ... -``` +``` \ No newline at end of file From 7fbf856d1c1c8aac0bf73f46fbce5322f2fffe49 Mon Sep 17 00:00:00 2001 From: Richard LASJUNIES Date: Fri, 8 May 2020 20:26:48 +0200 Subject: [PATCH 6/7] Fix test ... README.md is uppercase --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 46e34ab..73762d6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,7 @@ fn test_properties() { #[wasm_bindgen_test] fn test_component_readme() { - doctest!("concepts/components/readme.md"); + doctest!("concepts/components/README.md"); } #[wasm_bindgen_test] From 194eb8b873d43376384a93ed11346e32c1c1443e Mon Sep 17 00:00:00 2001 From: Richard LASJUNIES Date: Sun, 10 May 2020 17:33:22 +0200 Subject: [PATCH 7/7] Few cleaning based on Teymour feedbacks --- src/concepts/components/README.md | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/concepts/components/README.md b/src/concepts/components/README.md index f8da63f..f1bcebd 100644 --- a/src/concepts/components/README.md +++ b/src/concepts/components/README.md @@ -1,5 +1,5 @@ --- -description: Components and their lifecycle hooks +description: Introduction of Yew component --- # Components @@ -18,7 +18,7 @@ pub struct ExampleComponent { name: String, show_message: bool, - // properties and events bag + // properties and events struct props: Props, // link field supports the mechanism through which components are able to register callbacks and update themselves @@ -27,7 +27,7 @@ pub struct ExampleComponent { // enum of "Messages" that will be used to mutate the component state pub enum Msg { - Click(), + Click, } // definition of properties and events of the component @@ -54,18 +54,18 @@ impl Component for ExampleComponent { } } - // This method is executed each time the link.callbacks is called + // This method is executed each time the link.callbacks is called // you can mutate the state based on the message received fn update(&mut self, msg: Self::Message) -> ShouldRender { match msg { // mutate the component state - Msg::Click() => self.show_message = true, + Msg::Click => self.show_message = true, } true } - // mutate state if the properties bag is changed + // you can use change method to decide if you would like to re-render when properties change fn change(&mut self, props: Self::Properties) -> ShouldRender { if self.props != props { self.props = props; @@ -76,20 +76,19 @@ impl Component for ExampleComponent { } // Rendering of the component - // The method is called when 'ShouldRender' is 'true' as return of update and change method fn view(&self) -> Html { // different rendering depend on the component state if !self.show_message { html! { - // trap HTML events and trigger a message that will be managed in the update method - + // Listen to HTML events and trigger a message that will be managed in the update method + } } else { html! { // Use state value in the html -

{format!("Hello {}",self.name)}

+

{format!("Hello {}", self.name)}

} } } } -``` \ No newline at end of file +```