Skip to content

Latest commit

 

History

History
171 lines (139 loc) · 4.92 KB

intermediate-example.md

File metadata and controls

171 lines (139 loc) · 4.92 KB

A counter example

For our intermediate example, we will use the classic counter example.

We will start by creating a new rust library project called counter.

cargo new --lib counter

Modiy the Cargo.toml to be a library of crate-type "cdylib", since we are compiling it for a web application. Then add sauron to our dependency.

[package]
name = "counter"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
sauron = "0.50.0"

In this example we will show 3 buttons where can click to increment/decrement and reset the count. We will start by defining our model. Remove the contents of src/lib.rs put this code.

use sauron::prelude::*;

struct App {
    count: i32,
}

impl App {
    fn new() -> Self {
        App { count: 0 }
    }
}

We also added a function new to create our initial state of App which starts with count 0.

Next, we define out set of actions that our application will have. We will implement this using an enum with name Msg.

enum Msg {
    Increment,
    Decrement,
    Reset,
}

Next, we implement the Application trait for our model App. This is a way to define how our app should be displayed on page with the view method. Additionally, this also let us define how the App modifies its model with the update method. We also specify Msg to the Application trait which tells what type of messages that will be passed from events in the view, which also corresponds to the type we send into the update method.

Append this code to src/lib.rs.

use sauron::*;

impl Application for App {
    type MSG = Msg; 
    fn view(&self) -> Node<Msg> {
        node! {
            <main>
                <input type="button"
                    value="+"
                    on_click=|_| {
                        Msg::Increment
                    }
                />
                <button class="count" on_click=|_|{Msg::Reset} >{text(self.count)}</button>
                <input type="button"
                    value="-"
                    on_click=|_| {
                        Msg::Decrement
                    }
                />
            </main>
        }
    }

    fn update(&mut self, msg: Msg) -> Cmd<Msg> {
        match msg {
            Msg::Increment => self.count += 1,
            Msg::Decrement => self.count -= 1,
            Msg::Reset => self.count = 0,
        }
        Cmd::none()
    }
}

The view method creates a html node tree. Notice, that the return type is Node<Msg> which means it creates a html node where any of its member html elements has an event listener that can emit a Msg messages to the program handler. When a user clicks on the + button, this will emit an Msg::Increment message.

The update method accepts Msg as an argument and modify our model App depending on the variant of our Msg. For now, we return Cmd::none() at the end of the update method. Cmd is a way to tell the program to execute something, we will cover this in a more advanced example.

Next, we define an entry point for our wasm web app. This is done by anotating a public function with #[wasm_bindgen(start)].

Append this code to src/lib.rs.

#[wasm_bindgen(start)]
pub fn start() {
    Program::mount_to_body(App::new());
}

Inside this function, we define how our app is to be mounted into our index.html page. In this case we mount it to the body of our html page. The Program object provides other methods on how to mount your application into the document.

Next, we need to link our application in a html page.

Put this in index.html file at the project base folder. You can put your styles as usual.

<html>
  <head>
    <meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
    <title>Counter</title>
    <style type="text/css">
        body { font-family: verdana, arial, monospace; }
        main {
            width:30px;
            height: 100px;
            margin:auto;
            text-align: center;
        }
        input, .count{
            font-size: 40px;
            padding: 30px;
            margin: 30px;
        }
    </style>
    <script type=module>
        import init from './pkg/counter.js';
        await init().catch(console.error);
    </script>
  </head>
  <body>
  </body>
</html>

Make sure that the filename of the javascript file (./pkg/counter.js) in the import file matches the package name of your web app (counter). Double check this part of the code especially if you change the package name of your web app.

Compile the web app by issuing the command:

wasm-pack build --release --target=web

You need to issue this command everytime you modify the rust code.

Finally, serve the files using basic-http-server at port 4004

basic-http-server -a 0.0.0.0:4004

Then navigate your browser http://localhost:4004 to see and interact with the app.