-
-
Notifications
You must be signed in to change notification settings - Fork 929
m.route.setPath within lifecycle method breaks layout #1100
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
Comments
Fixed |
In a few very rare cases I'm able to get the double layout to occur even after the fix. Whenever it happens, it is immediately after Will try to get a jsfiddle of it happening up this week, but it doesn't appear to be predictable. Sometimes doing one thing will cause the issue, and sometimes that same thing works just fine. |
After a little bit of digging, I've found the solution but it breaks other tests. In short, wrapping the contents of I've tried this solution with I was also a little bit confused to find that Edit: instead of making everything async, it also works to just make the resolve part async |
Interesting. The fix I made was along those lines, but on this line: https://github.com/lhorie/mithril.js/blob/rewrite/router/router.js#L64 Perhaps it wasn't generic enough |
I looked into this some more, and discovered that the bug occurs after I've called const myComponent = {
oninit() {
m.redraw();
},
view() {
return m('div', 'foo');
}
}; The reason this could occur is that I had a component which, in its Here is the simpler version in action: https://jsfiddle.net/hwo1sctw/ It appears to only break when routing occurs. Replacing So, for the same reason that making It makes sense that redrawing within Edit: just realized this case is covered by the docs, too. |
@sebastiansandqvist It looks like calling |
@lhorie When redrawing, what should
|
Surely that's an application logic bug, and the initialisation code should know that an initial draw is forthcoming and therefore not trigger if the required data are already present? The case against allowing redraws when a view execution is forthcoming ( Asking for a redraw after view execution — As @isiahmeadows says, the recursive redraws in Exitable were a hack to get around shortcomings in the lifecycle framework. If we encounter use cases that seem to legitimate further hackery in v1, they should be treated as indicative of shortcomings in lifecycle documentation or implementation. For that reason I would keep behaviour undefined, and deal with problem cases holistically as and when they arise. |
@barneycarroll What do you think of my ideas, though? |
I don't like this. Redraws can be spammed and since Mithril doesn't offer concrete tools or opinions for model and control flow architecture, situations like @sebastiansandqvist's — whereby a component registers redraw dependency on streams and immediately triggers — isn't wrong. Arguably there's nothing wrong with this and the silent noop is a feature. If we had a verbose debug build of Mithril you might make the case of throwing a warning, but it's definitely wrong for Mithril to presume an error here. If the developer notices unexpected behaviour, they can come and report it in their own words.
This is what I was addressing above. A request to redraw before view execution is redundant; an explicit request to redraw within a view is a huge code smell and definitely shouldn't do anything IMO; a request to redraw immediately after DOM patching is either a code smell or an attempted hack that should be addressed holistically by the API.
As you say: violates the current implementation and doesn't have a use case. |
@barneycarroll I agree that it's a terrible idea to redraw within a view or in most other lifecycle methods, especially synchronously. But with events, or just in case the state legitimately goes stale within a lifecycle method for some odd reason (possibly due to circumstances outside Mithril's control), I feel queuing (or more accurately, requesting a subsequent redraw) is probably the appropriate thing to do. |
Could you elaborate on this point?
This isn't possible, since the lifecycle — once engaged by a draw — is sequentially synchronous. |
We should probably ditch the general lifecycle conversation here in favour of #1166 and reserve this thread for @sebastiansandqvist issue |
I'm moving this discussion to a new thread, since the original issue here has been addressed. See #1166 |
Description:
Using the rewrite, I am setting up user authentication in a method that is very much the same as seen here:
https://github.com/tivac/anthracite/blob/master/src/lib/require-auth.js
Expected:
I expected
m.route.setPath
to route me to/login
and erase the current page contents. It does not appear to matter which lifecycle method I put the routing logic in.Actual:
m.route.setPath
routed me to/login
but left the current page contents intact, displaying both pages simultaneously.I was able to fix this issue by wrapping
m.route.setPath('/login')
in arequestAnimationFrame
. I think it makes sense that mithril should handle this logic on the next frame, but if the library itself can handle that implementation detail I think it makes more sense being handled there than in component code.Edit:
I've created a minimal demo of this bug here using the rewrite:
https://jsfiddle.net/y8m56cg3/3/
There are interesting properties when combining this with a redraw:
https://jsfiddle.net/qs6b7qot/1/
https://jsfiddle.net/qs6b7qot/5/
https://jsfiddle.net/qs6b7qot/6/
And in some cases it can be fixed by wrapping
m.route.setPath
in asetTimeout
orrequestAnimationFrame
.https://jsfiddle.net/qs6b7qot/4/
This isn't always the case, but I haven't been able to reproduce the case where
setTimeout
doesn't solve the problem in a jsfiddle.And here it is working properly with 0.2.0:
https://jsfiddle.net/8zybnxf6/1
The text was updated successfully, but these errors were encountered: