DEV Community

Discussion on: Let's Build a Rust Frontend with Yew - Part 2

 
ademi profile image
ademi

Perfectly put :)

Thank for the detailed explanation, now it things make more sense!

For some reason I assumed that the child gets created ( the create method of the child gets called) at the parent html!{} closure, never which caused most of my confusion. While ,at least what I understand from your explanation, the child update function gets called at that stage.

As a follow up question, where would the child starts to exist? and how is the parameters get supplied to the create function?

Thanks again, and sorry for keeping coming back with more questions.

Thread Thread
 
deciduously profile image
Ben Lovy • Edited

Don't apologize! It's a good check to make sure I know what the heck I'm talking about too.

create() is only called once, in main():

fn main() {
  yew::initialize();
  let app: App<Model> = App::new();
  app.mount_to_body();  // <- right here
  yew::run_loop();
}

yew::initialize() is actually just stdweb::initialize(), it sets up the interop config.

The components are all created during mount_to_body. By the time we hit mount_to_body(), though, the html! macros have already expanded into a yew::virtual_dom::VNode tree, because macro expansion happened before the program was evaluated. The VDOM already is built at compile time, and create() is called with what you pass in in html!.

When we implemented the Component trait on this type, we created the ComponentLink struct. We don't use it in create, but it's still available to the component to use in update and change. This, through a few nested types, holds the pointer we need:

pub struct ComponentLink<COMP: Component> {
    scope: Scope<COMP>,
}

pub struct Scope<COMP: Component> {
    shared_component: Shared<Option<ComponentRunnable<COMP>>>,
}

struct ComponentRunnable<COMP: Component> {
    env: Scope<COMP>,
    component: Option<COMP>,           
    last_frame: Option<VNode<COMP>>,
    element: Element,
    ancestor: Option<VNode<COMP>>,     // <- right here
    occupied: Option<NodeCell>,
    init_props: Option<COMP::Properties>,
    destroyed: bool,
}

The update function is called every time a component receives a Msg. When the app is running, each component is sort of like an actor in the Actor model inside the event loop initialized with yew::run_loop().

Caveat to this answer being there's not much documentation or comments for me to source, but the Yew codebase is pretty small and generally readable. I believe I'm at least mostly correct :)

Thread Thread
 
ademi profile image
ademi

Fair enough,

To be honest, I couldn't yet swallow Rust way of doing things, but our conversation does clear a lot of my doubts.

Thanks a lot, Yew seems very powerful and promising framework. It's worth spending time studying the source code carefully.

Thanks again,
Cheers :)

Thread Thread
 
deciduously profile image
Ben Lovy

This code, too, isn't necessarily indicative of "normal" Rust, Yew imposes a rigid idiosyncratic model on top of it. Rust is a great, flexible language and i hope you continue to explore!

Thread Thread
 
ademi profile image
ademi

definitely!