Hola Amazing Devs π,
Welcome to the third episode of our Frontend Development in Rust and WebAssembly blog series. Earlier, we have understood the basics of WebAssembly and set-up the development environment.
Now, let's start with our first application: Social Media Application in Rust + Yew. So buckle up your seat belts as we'll be doing the Rust WASM Magic πͺ. Also you can follow along if you'd wish to :)
Well, in this episode we'll start with a login form and in the next episodes we'll proceed ahead.
Prerequisites
- Cargo and Rust is required.
- Compilation target for WebAssembly must be added, for Rust to compile into WebAssembly:
rustup target add wasm32-unknown-unknown
- Next up, we require trunk for serving Yew applications:
cargo install --locked trunk
Setting up a new Yew project
Follow the steps in the previous blog in this series (until step 4) to set up a new Yew project. After that, we'll end up with a src/main.rs file with some relevant Yew code and an index.html file in the root directory.
use yew::prelude::*;
#[function_component]
fn App() -> Html {
html! {
<h1>Hello from rust in browser π¦π</h1>
}
}
fn main() {
yew::Renderer::<App>::new().render();
}
The flow
We'll create a function component
LoginForm
. This will contain the state variables for username, password and login message, the change handling methods for our inputs and a method for handling form submission. And finally, we'll have to return the Html Template by this function component (html!
).html!
is a type provided by Yew which helps write html like template code in Rust, just like JSX. This is a blessing from Yew π₯Ή.Then we just call our
LoginForm
component from ourApp
.And finally, we'll render the
App
within main method.
Writing the component
- Navigate to
src/main.rs
, and add the following code right aboveApp
function:
use web_sys::HtmlInputElement;
#[function_component(LoginForm)]
fn login_form() -> Html {
let username = use_state(|| "".to_string());
let password = use_state(|| "".to_string());
let message = use_state(|| "".to_string());
let on_username_input = {
let username = username.clone();
Callback::from(move |e: InputEvent| {
let input = e.target_unchecked_into::<HtmlInputElement>();
username.set(input.value());
})
};
let on_password_input = {
let password = password.clone();
Callback::from(move |e: InputEvent| {
let input = e.target_unchecked_into::<HtmlInputElement>();
password.set(input.value());
})
};
let on_submit = {
let username = username.clone();
let password = password.clone();
let message = message.clone();
Callback::from(move |_| {
if *username == "dev.to" && *password == "dev.to" {
message.set("Login successful!".to_string());
} else {
message.set("Invalid username or password.".to_string());
}
})
};
html! {
<div>
<h1>{ "Login" }</h1>
<input
type="text"
placeholder="Username"
value={(*username).clone()}
oninput={on_username_input}
/>
<input
type="password"
placeholder="Password"
value={(*password).clone()}
oninput={on_password_input}
/>
<button onclick={on_submit}>{ "Login" }</button>
<p>{ (*message).clone() }</p>
</div>
}
}
This code defines a function component with the name LoginForm
, with three states: username
, password
and message
, with empty strings as their initial values.
Then, at the last we are returing an HTML Template with a login form. Note that we are giving the values for inputs as *(input_state).clone()
as we are in the closure, similarly we are doing for the message
.
Also, for both of the inputs and the for the button, we are passing handlers. (the oninput
and onclick
).
In the input handler callbacks, we are just cloning the states, listening for the InputEvent
, typecasting it to HtmlInputElement and setting the state to its value after typecasting. Since HtmlInputElement is from the crate web_sys, we also need to import it in our main.rs file and mention it as a dependency in Cargo.toml. Cargo.toml should look like:
[package]
name = "wasm-dev"
version = "0.1.0"
edition = "2021"
[dependencies]
yew = { git = "https://github.com/yewstack/yew/", features = ["csr"] }
web-sys = "0.3"
Now in the onsubmit handler, we check if the username and password values are correct, then we change the error message accordingly.
And do not forget to call our LoginForm
component in the App
component and render App
in the main function:
#[function_component(App)]
fn app() -> Html {
html! {
<LoginForm />
}
}
fn main() {
yew::Renderer::<App>::new().render();
}
Finally we do: trunk serve
and navigate to `localhost:8000
and Tadaa π:
We have our login form, written in Rust π.
Let's try example
as username and example
as password, you'll see te following message:
And trying the correct credentials: dev.to
and dev.to
:
Hurray, we made it.
So, this is it for today, in later blogs, we'll complete the authentication part and then create a news feed.
Final code can be found here on Github.
See you next week. Adios, Amigos π
Top comments (0)