-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to call a method or dispatch a Msg on a child element, WITHOUT re-rendering parent DOM? #350
Comments
While I can't guarantee that this will solve your problem, have you tried using an agent(s) to mediate message passing after your WS returns a response?
A workflow would work as follows:
I have code for this scenario accessable from this issue: #301 You could use the above solution or you could handle websockets in every relevant component (difficult to implement), or just stick the WS in an agent, and have the agent itself dispatch messages to different receivers depending on the response. This WS agent would replace the multitude of sender agents that would be required if you took the sender+receiver approach. |
Thanks, but this issue is more fundamental than my WS situation, the general issue that needs to be solved in Yew is: self.child(ChildSlot::ChildA).update(child_a::Msg::Foo(..)); When we instantiate it in html! { <MyChild #ChildSlot::ChildA: prop=val, /> } Which is almost as convenient as in Halogen, except it requires a runtime type-check during downcasting whereas in Halogen it's all checked at compile-time. And then we could also query children with responses like: let resp = self.child(ChildSlot::ChildA).query(child_a::Msg::GiveMeSomeAnswer); Wouldn't you agree that this kind of child querying would be way more convenient? :) I left some impl details out here (e.g. Btw, I encourage everyone to become familiar with the Halogen framework, to get ideas how we can make Yew more convenient to use. Currently, Halogen is much nicer to use than Yew (mostly because of this issue with parent-child communication but also because Halogen supports inline/async-await handling of queries/ajax etc.) but I wish Yew would become equally convenient, so that we can use it on large-scale apps without missing the convenience of Halogen.. |
@Boscop This seems to be an interesting topic, but unfortunately I don't understand Halogen or PureScript (or Haskell which it's similar with). It seems to me that Vue's Random note: Vue's change tracking model doesn't require any code deciding on "re-render" or not; thus I wonder if Halogen queries has any additional benefits than performance. While Vue is very different from React or Yew, would you call Vue's design convenient? |
@ishitatsuyuki It seems to be a similar mechanism as in Polymer, but it is not a query algebra, it's just a way to specify (by name) which method should handle an event. But it is completely weakly typed.. Btw, it seems that draco (another Rust wasm web framework) allows updating child widgets' state without forcing a re-render of the parent's DOM: What do you think? :) I also think, if we do this, self.btn.eval(ChildMsg::IsOn(|on| MyMsg::HandleIsOn(on)); This will basically pass a callback to the child's You may be asking "why can't we just call
So the best way (IMO) would be to go with both suggested solutions (having children as members of components, and #435) because they work well together. |
Missing label:
|
There is a way to do this as shown in https://github.com/yewstack/yew/blob/master/examples/nested_list/src/app.rs I've created an issue to write some documentation about this approach here: #905 |
Is there a way to pass a reference of the actual component instead that a link? I would prefer to not import the
Do something like:
I don't think there will be a big advantages using the second solution maybe just a bit more readable, I'm asking just out of curiosity. |
@Fi3 I think the second pattern is possible but it would be quite a big effort and I'm not sure the benefit would be big enough. Another pattern you could use is |
We could make this pattern even easier with a small API change: #932 |
@Fi3 Yes, it's possible by introducing your own trait, it doesn't even need to be in Yew. |
How to call a method or dispatch a Msg on a child element?
Or is the only way to cause a child to do something to change an attribute/property that is passed to it?
In my use case, the main app element wants to update the state of the child element after receiving new data over websockets, and ONLY that child element's DOM should be re-rendered!
How can I update a child element's state, so that only that child's DOM is re-rendered?
Currently, it updates the whole app's DOM every time a ws state update is received, which is unnecessary because every ws msg only affects a specific child element. So I want to be able to dispatch direct msgs on a child so that only that child's DOM gets re-rendered. Similar to how PureScript's Halogen framework allows querying child components:
Here is an example of an action query, which doesn't return a value ("child, do X").
Here is an example of a request query, which returns a value ("child, tell me X").
(In Halogen, queries can be used both for commands (actions) and requests (returning values from child to parent), they don't trigger a re-render of the parent's DOM. The query will be dispatched by the child's own
eval
method (likeupdate
in yew) and will only cause the child's DOM to be re-rendered if its own state changes as a result of handling this query.)If I pass the state updates down through attributes/properties, it's suboptimal in many ways:
true
fromupdate
(ShouldRender
) JUST to be able to pass this state to the child (yew only passes properties down to children when the parent re-renders its own DOM, right?), which would re-render the WHOLE parent (app) DOM, but only the child's state should change, and ONLY the child's DOM should be re-rendered.I think the fact that currently, my whole app's DOM is re-rendered on every websocket message that's received (it's receiving msgs at ~30 fps) is the cause of the high CPU usage (#351) (even though each ws msg should only affect state change in 1 small child (small meaning "small DOM surface" compared to the whole app) and should also only trigger a re-render of that small child's DOM).
And the fact that the parent has to keep clones of all children's states around, just to be able to pass them down to the children as properties during DOM re-rendering also means that the app uses much more memory than it would use, if it could dispatch msgs on child elements directly, and move the data instead of cloning.
EDIT: Also, doing the equivalent of a Halogen-like request query (with value returned from child to parent) in yew would involve even more steps and would obscure the communication even more! The steps are:
Msg
enum that represents a response of the request from the child (wouldn't be necessary in Halogen. Querying the child can be done 'inline' in the parent'seval
(update
) method and does NOT disrupt the control flow / reading flow. Just like ajax requests in Halogen, whereas in Yew they require anotherMsg
case with handling code, like in Elm. In Halogen, they can also be done 'inline' like writing futures code.)child_req: Option<ChildReq>
.childreq: Option<ChildReq>
andonchildreq: Option<Callback<()>>
to theProps
andModel
of the child's struct.childreq
andonchildreq
fromProps
toModel
inModel::create
andModel::update
.Model::create
andModel::update
for whenprops.childreq
isSome(req)
, perform the action and respond by callingonchildreq
to return the value back to the parent.update
method of the parent, write the handling code for the response from the child. Note that the code that sent the request to the child and the code that processes the child's response are separated (differentMsg
variant handler branches in the match statement) which makes it harder to read what's going on, ESPECIALLY when the parent has a lot of children that it needs to query, which is quite common in real-world apps! (E.g. in the frontends I'm writing for my job, where I'm using Halogen.)The text was updated successfully, but these errors were encountered: