I guess my question is: what's the type of the parameter msg in that line, i tried to rewrite the line as |msg:Option>|msg but that threw a compiler error.
and how does the child entity have access to the parent instance?
The type of msg here is simply crate::Msg. The trick is that the onsignal prop is a closure, and the return value of the closure is a Yew message. This whole closure is the prop that's passed in as a callback. When this closure is invoked Yew will dispatch whatever message it's called with via the lib.rsupdate function. The actual call happens in the child:
callback.emit() is where the parent event is actually fired. The specific message that's getting passed up is pulled out of ButtonPressed(msg). When the ButtonPressed event happens as a result of the onclick handler, the child component checks to see if there is was a callback provided by the parent - there is, it's |msg| msg. Then it emits that callback, filling in msg with the message provided by the ButtonPressed event, which will be a crate::Msg::SwitchRoom() with the right target room. This is why you got a compiler error - right here you're promising to call it with a crate::Msg, without the option. You're correct in assuming the source of that error should probably be where you were putting it, not the child component - it's the child that should complain and prompt you to use the correct type. Unfortunately the html! macro expansion obfuscates this because it expands prior to actually evaluating and throws first. At least as far as I understand it.
So, the child can't really see the parent, it just invokes the closure that the parent passed in as a prop.
Does that answer your question? I find callbacks a little tricky to talk about clearly, so let me know if I'm just making it more confusing.
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.
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():
fnmain(){yew::initialize();letapp:App<Model>=App::new();app.mount_to_body();// <- right hereyew::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:
pubstructComponentLink<COMP:Component>{scope:Scope<COMP>,}pubstructScope<COMP:Component>{shared_component:Shared<Option<ComponentRunnable<COMP>>>,}structComponentRunnable<COMP:Component>{env:Scope<COMP>,component:Option<COMP>,last_frame:Option<VNode<COMP>>,element:Element,ancestor:Option<VNode<COMP>>,// <- right hereoccupied: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 :)
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!
Great! Thanks for entertaining me.
I guess my question is: what's the type of the parameter msg in that line, i tried to rewrite the line as |msg:Option>|msg but that threw a compiler error.
and how does the child entity have access to the parent instance?
Thanks for entertaining my doubts :)
The type of
msg
here is simplycrate::Msg
. The trick is that theonsignal
prop is a closure, and the return value of the closure is a Yew message. This whole closure is the prop that's passed in as a callback. When this closure is invoked Yew will dispatch whatever message it's called with via thelib.rs
update
function. The actual call happens in the child:callback.emit()
is where the parent event is actually fired. The specific message that's getting passed up is pulled out ofButtonPressed(msg)
. When theButtonPressed
event happens as a result of theonclick
handler, the child component checks to see if there is was a callback provided by the parent - there is, it's|msg| msg
. Then it emits that callback, filling inmsg
with the message provided by theButtonPressed
event, which will be acrate::Msg::SwitchRoom()
with the right target room. This is why you got a compiler error - right here you're promising to call it with acrate::Msg
, without the option. You're correct in assuming the source of that error should probably be where you were putting it, not the child component - it's the child that should complain and prompt you to use the correct type. Unfortunately thehtml!
macro expansion obfuscates this because it expands prior to actually evaluating and throws first. At least as far as I understand it.So, the child can't really see the parent, it just invokes the closure that the parent passed in as a prop.
Does that answer your question? I find callbacks a little tricky to talk about clearly, so let me know if I'm just making it more confusing.
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.
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, inmain()
: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 hitmount_to_body()
, though, thehtml!
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, andcreate()
is called with what you pass in inhtml!
.When we implemented the
Component
trait on this type, we created theComponentLink
struct. We don't use it increate
, but it's still available to the component to use inupdate
andchange
. This, through a few nested types, holds the pointer we need:The
update
function is called every time a component receives aMsg
. When the app is running, each component is sort of like an actor in the Actor model inside the event loop initialized withyew::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 :)
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 :)
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!
definitely!