Skip to content
This repository has been archived by the owner on Jul 19, 2020. It is now read-only.

1/8 Create lifecycle page and review component introduction #82

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@
* [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)
* [Life cyle](concepts/components/lifecycle.md)
* [Agents](concepts/agents.md)
* [Services](concepts/services/README.md)
* [Format](concepts/services/format.md)
Expand Down
196 changes: 56 additions & 140 deletions src/concepts/components/README.md
Original file line number Diff line number Diff line change
@@ -1,143 +1,71 @@
---
description: Components and their lifecycle hooks
description: Introduction of Yew component
---

# 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:
## Example of component

```rust
pub struct MyComponent {
props: Props,
link: ComponentLink<Self>,
}
use yew::prelude::*;

impl Component for MyComponent {
type Properties = Props;
// ...
pub struct ExampleComponent {
// state of the component
name: String,
show_message: bool,

fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
MyComponent { props, link }
}
// properties and events struct
props: Props,

// ...
// link field supports the mechanism through which components are able to register callbacks and update themselves
link: ComponentLink<Self>,
}
```

### 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! {
<button onclick=onclick>{ self.props.button_text }</button>
}
}
// enum of "Messages" that will be used to mutate the component state
pub enum Msg {
Click,
}
```

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.
// definition of properties and events of the component
#[derive(Properties, Clone, PartialEq)]
pub struct Props{
#[prop_or("Superman".to_string())]
pub name: String,

```rust
use stdweb::web::html_element::InputElement;
use stdweb::web::IHtmlElement;
use yew::prelude::*;

pub struct MyComponent {
node_ref: NodeRef,
#[prop_or_default]
pub onmyclickevent:Callback<String>,
}

impl Component for MyComponent {
// ...

fn view(&self) -> Html {
html! {
<input ref=self.node_ref.clone() type="text" />
}
}
impl Component for ExampleComponent {
type Message = Msg;
type Properties = Props;

fn rendered(&mut self, first_render: bool) {
if first_render {
if let Some(input) = self.node_ref.try_into::<InputElement>() {
input.focus();
}
// Initialization of the state
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
Self {
link,
props: props.clone(),
name: props.name.into(),
show_message: false,
}
}
}
```

{% 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;

// ...

// 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 {
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.
match msg {

A typical implementation would look like:

```rust
impl Component for MyComponent {
// ...
// mutate the component state
Msg::Click => self.show_message = true,
}
true
}

// 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;
Expand All @@ -146,33 +74,21 @@ impl Component for MyComponent {
false
}
}
}
```

### 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,
// Rendering of the component
fn view(&self) -> Html {
// different rendering depend on the component state
if !self.show_message {
html! {
// Listen to HTML events and trigger a message that will be managed in the update method
<button onclick=self.link.callback( |_| Msg::Click )>{"Click to say hello!"}</button>
}
} else {
html! {
// Use state value in the html
<h1>{format!("Hello {}", self.name)}</h1>
}
}
}
}
```

`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.

Loading