Closed zaceno closed 6 years ago
@zaceno getState
does not cause a re-render.
const actions = {
getState: () => state => state
}
@JorgeBucaran It doesn't? Oh is that the immutability-thing? Ok, well then it's not so bad :) (It's still not the most pleasing api, but that's ok. The main issue I had with it was that I thought it would cause the merge ti run through, and at least a call to repaint
and possibly render
.)
@zaceno It will not even cause a merge. When you call getState
, we'll produce a state slice for the action (the correct paths to obtain it are stored inside the action closure), then we'll call the action with it. If the action returns the same slice, we'll skip both merge
and repaint/render
and return immediately.
Performance optimizations for the win! 🍻
@zaceno What do you say we compromise this with getState
?
@JorgeBucaran yes I think that's the way to go for now!
👍
Abstract / TL;DR; When you try to access the state asynchronously in the view, like in
onbeforeremove
or insetTimeout
called in event handlers, the state will be stale. There are workarounds, but they are not ideal.The long version:
If you define a function inside the view, which will be called at a later time, that function will not have access to the current state at the time it is called. If you try, the state you get will be stale. This means, for example, you cannot rely on state inside
onbeforeremove
handlers, or insetTimeout
s called in event handlers. For a concrete demonstration of this problem, see this example of a carousel:https://codepen.io/zaceno/pen/WdrZdK
I'm using hyperapp-transitions in order to have a not too contrived, but still short, example. All you need to know is that
1)
transitions.exit
runs the transition in theonbeforeremove
handler. 2) The function passed to thecss
prop is called at the time of the transition, in this case to determine the direction to exit/enter. (Since it depends on where the user clicked)Notice when you click the buttons of the carousel that as long as you times in a row, the new images slide in the same direction as the old images slide out. But every time you switch directions, the image leaves according to the old direction, while the new image slides in from the correct direction.
The explanation for this, is that the exit transition (and hence
onbeforeremove
handler, has the old state in it's closure) -- it hasn't ever even seen the new state, since it's no longer in the vtree (that's why its being removed).There are, of course, workarounds...
One way to solve it, would be to keep an up to date copy of the relevant state somewhere, accessible by the functions that need it. That's how I solved it for the caruousel example in this codepen:
https://codepen.io/zaceno/pen/LeGQab?editors=0010
See especially lines 14, 32, 37, 38. Notice how now when you switch directions, it works as intended. This works for the occasional one off, but is obviously far from ideal.
Another solution is to use an action (since actions are special, and always have access to the current state when they're called), relying on the fact that actions return their partial state. See:
https://codepen.io/zaceno/pen/ZvQrgE?editors=0010 (notice lines 14, 16, 22)
This solution is better than the previous, but also unsatisfying (for me at least). It's annoying that simply accessing the state will cause an update and rerender.