Skip to content
This repository was archived by the owner on Jul 19, 2020. It is now read-only.
Open
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
Comp readme update + add life cyle page
  • Loading branch information
Richard LASJUNIES committed May 8, 2020
commit c7100a7a45a4dcc19323f1837fc745a4ae4af0f3
1 change: 1 addition & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
173 changes: 23 additions & 150 deletions src/concepts/components/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<Self>,
}

impl Component for MyComponent {
type Properties = Props;
// ...

fn create(props: Self::Properties, link: ComponentLink<Self>) -> 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! {
<button onclick=onclick>{ self.props.button_text }</button>
}
}
}
```

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! {
<input ref=self.node_ref.clone() type="text" />
}
fn create(_props: Self::Properties, _link: ComponentLink<Self>) -> Self {
Self {}
}

fn rendered(&mut self, first_render: bool) {
if first_render {
if let Some(input) = self.node_ref.try_into::<InputElement>() {
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! {
<>
<h1>{"Hello World!"}</h1>
</>
}
}
}
```

### 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
...
<SimpleComponent />
...
```

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

167 changes: 167 additions & 0 deletions src/concepts/components/lifecycle.md
Original file line number Diff line number Diff line change
@@ -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<Self>,
}

impl Component for MyComponent {
type Properties = Props;
// ...

fn create(props: Self::Properties, link: ComponentLink<Self>) -> 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! {
<button onclick=onclick></button>
}
}
}
```

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! {
<input ref=self.node_ref.clone() type="text" />
}
}

fn rendered(&mut self, first_render: bool) {
if first_render {
if let Some(input) = self.node_ref.try_into::<InputElement>() {
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.
5 changes: 5 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}