YEW Tutorial: 02 Extending the example
Tags: rust, webassembly, yew
Published: 2020-04-12 10:31:27

Cover photo by Daria Nepriakhina on Unsplash; the banana, after Cattelan's exposition, is coming to signify the message of deceptive simplicity.

In this second part we are going to do some extensions/improvements,
and hopefully show a little more of the potential
of [Yew framework](https://yew.rs)

In this article we will be tinkering around, in order to understand better the concepts
at work in Yew. We will do also some project related stuff, which is more general or more front-end specific, and less related with Yew. Let's go!

### Code to follow this tutorial

The code has been tagged with the relative tutorial and part.

```Bash
git clone https://github.com/davidedelpapa/yew-tutorial.git
cd yew-tutorial
git checkout tags/v2p0
```

## Let's script our way through the boring stuff

But first a little improvement that will help us a lot.
Let's create a file called _run.sh_

### run.sh

This script's' purpose is simple: automate the build and run of this project.

```bash
#!/bin/sh

build(){
    wasm-pack build --target web
}

pack(){
   rollup ./main.js --format iife --file ./pkg/bundle.js
}

run(){
    python -m "http.server" "8080" &
    PID=$!
    echo $PID > .serverpid
}

build
pack
run
```

At the top of the script we have the shebang, `#!/bin/sh`,that tell the console interpreter which environment use.
Of course, _sh_ **is not** _bash_, but as long as you are posix compliant in your scripts, it doesn't matter. I personally use [zsh](http://www.zsh.org/) with the fabulous [Oh My Zsh!](https://ohmyz.sh/), but these are personal preferences. Back to work, now.

We divided the actions to be done in 3 functions that we call at the end.
It is important to be modular, because in this way we can modify independently each one of the functions.

- the function _build_ calls up the `wasm-pack` as we have seen in the previous post
- the function _pack_ calls up the `rollup` as seen in the previous post.

The _run_ function deserves special attention. We are not simply calling the server, we are making it work in background (the `&` appended to the command). For this reason we are saving the process' PID and storing it in a hidden file, _.serverpid_

**Quick troubleshooting**: if you have both python2 and python3 installed on your system, and the script is not working, saying it can't recognize the http module

```bash
/usr/bin/python: No module named http
```

try calling straight python 3, for example `python -m "http.server" "8080" &`

Now that it is done, let's make it executable.

```bash
chmod u+x run.sh
```

Finally we can execute it easily with:

```bash
./run.sh
```

Yatta! All working well. But if we wish to stop the server? We need to look at the process' pid we stored earlier

```bash
cat .serverpid
```

Right now for me is `10859`
I can stop it, therefore with:

```bash
kill 10859
```

Done!

Now we'd better make an automated script to do just that-

### stop.sh

The script is modular as well, maybe its overkill, but better be prepared for more.

```bash
#!/bin/sh

stop(){
    if [ -f .serverpid ]; then
        kill $(cat .serverpid)
        rm .serverpid
        echo Server stopped
    else
        echo Could not find the server PID. Is it running?
    fi
}

stop
```

- We check for the existence of _.serverpid_ and we kill the process with the pid written in it
- We alert the user both in the case the pid was not found and in the case all went well.

Now we have two scripts to help us going on with the project (remember to make _stop.sh_ executable!)

## Extending our example app

After this detour we can go on with the Yew tutorial.
Without further ado, let's thinker around with the code inside our _src/app.rs_

### Part 1: Add a new message

#### Code to follow this part

```Bash
git checkout tags/v2p1
```

First of all, let's add a new message, let's say, to decrease the counter.

```rust
pub enum Msg {
    AddOne,
    RemoveOne,
}
```

Now we need to take care of handling the logic of this new message:

```rust
    fn update(&mut self, msg: Self::Message) -> ShouldRender {
        match msg {
            Msg::AddOne => self.counter += 1,
            Msg::RemoveOne => self.counter -= 1,
        }
        true
    }
```

Quite simply, we added a match branch and we did something with that message.

It is now time to add a button to the DOM, in order to send this new message.

```rust
    fn view(&self) -> Html {
        html! {
            <div>
            <p> {"Counter: "} { self.counter }</p>
                <button onclick=self.link.callback(|_| Msg::AddOne)>{ "Add 1" }</button>
                <button onclick=self.link.callback(|_| Msg::RemoveOne)>{ "Remove 1" }</button>
            </div>
        }
    }
```

This too is quite self-explanatory. Let's check it out starting the server.

![Our first improvement](https://dev-to-uploads.s3.amazonaws.com/i/92s7s0fg5u6e6k0bzpji.jpg)

Well good. We can even go negative if we want. What about implementing the logic to avoid negative numbers, but stop to `0`? Can you implement it? (My solution in code)

### Part 2: What if we want to handle a list instead

#### Code to follow this part

```Bash
git checkout tags/v2p2
```

What if we want the counter instead to be a list, and increase the elements of that list?
This is plain ol'Rust, let's do it!

First of all, let's modify _counter_ to be a `Vec<i64>`. Actually, the name "counter does not make sense anymore, so let's rename the symbol too:

```Rust
pub struct App {
    items: Vec<i64>,
    link: ComponentLink<Self>,
}
```

We need to update our component constructor as well, the _create_ function:

```Rust
    fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
        App { link, items: Vec::new() }
    }
```

Of course, we can't simply add to the a `Vec`, we need to update the _update_ logic!
Well... What are we going to push inside of it? For now just a random number!

Wait! How do we add a random number?
We need first of all get into our dependencies the crate [rand](https://crates.io/crates/rand), which supports compiling to the WASM through [getrandom](https://crates.io/crates/getrandom)

In _Cargo.toml_ add to the `[dependencies]`:

```Toml
rand = { version = "0.7", features = ["wasm-bindgen"] }
```

To call the `random()` function, we have to `use` the preamble in _src/app.rs_

```Rust
use rand::prelude::*;
```

Then we can change the handling logic in `update`:

```Rust
    fn update(&mut self, msg: Self::Message) -> ShouldRender {
        match msg {
            Msg::AddOne => self.items.push(random()),
            Msg::RemoveOne => {
                self.items.pop();
            }
        }
        true
    }
```

Why would we need to wrap the remove branch of the `match` in brackets? Remember that `pop()` returns an _Option_ (the popped element or `None`), while push returns `()`.

Finally we have to display our trusty vec:

```Rust
    fn view(&self) -> Html {
        html! {
            <div>
            <p> {"Items: "} { format!("{:?}", self.items) }</p>
                <button onclick=self.link.callback(|_| Msg::AddOne)>{ "Add 1" }</button>
                <button onclick=self.link.callback(|_| Msg::RemoveOne)>{ "Remove 1" }</button>
            </div>
        }
    }
```

A vector does not implement Display, so we take advantage of the debug formatting.
In fact, all handy tools are still available to us:
Rust's still Rust even compiled to WASM.

We can now run and check the results.

![Some randomness](https://dev-to-uploads.s3.amazonaws.com/i/p2tgtimjdp93d2zyw262.jpg)

Well, I added some random items.

OK, but should we not do something useful instead of just Rusting around?
Hold your horses cowboy, we first need some more understanding of how to work in Rust with WASM, and the Yew framework.

### Part 3: Display the Vec the nice way

#### Code to follow this part

```Bash
git checkout tags/v2p3
```

Rust's `format!` is great and all, but sure displaying a vec in debug mode is not that great frontend practice, is it?

Let's remedy to that, by changing our `view`

```Rust
    fn view(&self) -> Html {
        let render_item = |item| {
            html! {
                <>
                    <tr><td>{ item }</td></tr>
                </>
            }
        };
        html! {
            <div class="main">
                <div class="card">
                    <header>
                        {"Items: "}
                    </header>
                    <div class="card-body">
                        <table class="primary">
                            { for self.items.iter().map(render_item) }
                        </table>
                    </div>
                    <footer>
                        <button onclick=self.link.callback(|_| Msg::AddOne)>{ "Add 1" }</button> {" "}
                        <button onclick=self.link.callback(|_| Msg::RemoveOne)>{ "Remove 1" }</button>
                    </footer>
                </div>
            </div>
        }
    }
```

Whaaat? Stop the world it's spinning too fast!

We are using a CSS framework here, [picnic](https://picnicss.com/), and we are using a recursion over the vector in order to create rows of a table.

Lets go in order.
We added a lot of HTML tags and CSS classes, but really what has changed is just the following:

```Rust
{ for self.items.iter().map(render_item) }
```

This notation starting with a for iterates over the vec `self.items` and maps the results to a closure, _render_item_.

Let's see what this closure does, then.

```Rust
let render_item = |item| {
    html! {
        <>
            <tr><td>{ item }</td></tr>
        </>
    }
};
```

This closure returns a `html!` using **fragments**.

Fragments are a couple of empty tags `<>` and `</>`. This is the way Yew has to nest code for `html!` inside another. Since this macro can have just one starting point in the DOM, fragments manage the nesting for us.

For the rest, there is really no other new thing, except for a lot of new HTML and CSS classes. And a little caveat:

```Rust
{" "}
```

This fragment between the two buttons is really important, in order to let _Yew_ play nice with _picnic_ buttons.

Before running the project we have to remember to update the index.html as well, in order to call `picnic`, otherwise there is no point in all those CSS classes.

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Yew Tutorial</title>

    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="stylesheet" href="https://unpkg.com/picnic" />
    <script src="/pkg/bundle.js" defer></script>

    <style>
      .main {
        max-width: 800px;
        margin: auto;
      }
      .card-body {
        margin: auto;
      }
    </style>
  </head>
  <body></body>
</html>
```

I added 2 styles as well, just to show that you can still integrate Yew with all the usual styling methods.

Finally, we have also to increase the recursion limit if we want our `html!` macro to compile.
In fact, in order to put more elements in the `html!` macro the default limit is too tight.

In _src/lib.rs_

```Rust
#![recursion_limit = "256"]
mod app;
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn run_app() -> Result<(), JsValue> {
    yew::start_app::<app::App>();

    Ok(())
}
```

We can run and see the rewards of our efforts!

![Our reward!](https://dev-to-uploads.s3.amazonaws.com/i/6k4ik4p67fjm0a55bdgn.jpg)

We will continue in the next installment of this tutorial talking about services.