I have a page on which a lot of widgets. All widgets frequently polls the server. And one of these widgets is the timer that simply shows the time and it has no any business logic. Timer ticks every second and every second WHOLE view is rerendered! But I want to make this a timer ticking, and only changed his view. Is there any do it or I in all cases is to use the state?
Can you try using a separate model for the timer widget with its own namespace? Maybe that could fix it? I think the name of this issue should be renamed though to "whole page is rendering when only a few items changed" or something like that. Also it might be helpful if we can see your code so we can view the implementation.
@MattMcFarland I originally did so, but every view in my project updated with every tick.
Here example of my model
module.exports = {
namespace: 'timer',
state: {
time: new Date()
},
reducers: {
setTime: (data, state) => ({ time: data })
},
effects: {
updateTime: (data, state, send, done) => {
send('timer:setTime', data, done)
}
},
subscriptions: [
(send, done) => {
setInterval(() => {
send('timer:updateTime', new Date(), done)
}, 1000)
}
]
}
@kwoon ah yeah, that's what happens with virtual-dom renders; to change a single element the whole page is re-computed and the minimal amount of changes are performed on the actual DOM.
A way to improve the rendering speed is to use thunking for individual components on the page. Given the same input, the same output is returned. The vdom-thunk package should be helpful for that.
Does this answer your question?
Ahhh, this must be what caused codemirror to lose focus.
@yoshuawuyts Thanks! It is even better than i expected! Just like shouldComponentUpdate in React.
@yoshuawuyts wait, but choo use yo-yo which uses morphdom which is not virtual dom right? So the view should update properly if yo-yo#update is used? or I'm confused :question:
@YerkoPalma I think this is not the best name for the package. The functionality of this package is much wider.
@kwoon what package?
@YerkoPalma vdom-thunk
@YerkoPalma I agree, I'm not sure how vdom-thunk is going to work with morphdom?
@kwoon can you share an example when you get it working?
related issue https://github.com/shama/bel/issues/40
Well I understand the thing about the thunk function, My only doubt is why does a vdom library fits with a non vdom library?
@YerkoPalma I think this is not the best name for the package. The functionality of this package is much wider
Is that why? the vdom thunk is also compatible with native dom?
So yeah, the vdom-thunk package is compatible with bel components - from the source all code is pretty much only about copying function parameters.
The implementation does feel a bit too complicated for my taste though; it does some stuff with objects and keys that feels off. For bel components we could def create a simpler version of this package
Ok, I'm starting to understand :smile: but from the related issue there is this comment
Initially it feels like this should be in the diffing library or yo-yo as bel doesn't know about previous elements.
I agree with that, I feel like choo should enforce or recommend the use of the yoyo update function, and update that function if necesary, I don't know why the thunk function should be in bel library
I don't know why the thunk function should be in bel library
I feel the goal of bel is to create standalone components that work anywhere.
Like onload and onunload provide hooks into any DOM abstraction, thunk
would provide a way to optimize those components.
The way I view a typical element in bel would be along these lines:
const thunk = require('bel/thunk')
const assert = require('assert')
const html = require('bel')
module.exports = thunk(createMyButton)
// create a button that has a color, a value inside it
// and does a thing when clicked
// (str, str, fn(clickEvent)) -> str
function createMyButton (opts, onclick) {
opts = opts || {}
assert.equal(typeof opts, 'object')
assert.equal(typeof onclick, 'function')
const color = opts.color || 'blue'
const name = opts.name || 'click'
return html`
<button onclick=${onclick} style="background-color: ${color}">
${name}
</button>
`
}
Using this component would be the same for pretty much any framework, but now
it's optimized for re-rendering / vdom trees. Using it in choo would look
like this:
const html = require('choo/html')
const Button = require('../elements/my-button')
// model bound to this particular view
const model = {
namespace: 'button',
state: {
color: purple,
name: 'click me!'
},
effects: {
hey: () => console.log('hey!')
}
}
module.exports = sectionView
sectionView.model = model
// A button with a button in it
// (obj, obj, fn) -> str
function sectionView (state, prev, send) {
const button = Button(state.button, (e) => send('section:hey'))
return html`
<section>
<h1>Hello y'all</h1>
${button}
</section>
`
}
I feel like thunk is an integral part to creating components in such a way, I
can't think of a time where it wouldn't make sense to thunk an element. Does
this clarify it a little?
Pretty clear now, thanks. :)
Man I had to make sure codemirror was fully rendered first and that was not easy to figure out.
https://github.com/trainyard/choo-codemirror
would be nice if there was a way to completely ignore parts of the dom. like special portals or something.
Oops, found a bug in my code. In order to prevent multiple instances of the same element conflicting on the page, the export should be wrapped in a function. E.g.
// oops
module.exports = thunk(createMyButton)
// phewwww
module.exports = function () {
return thunk(createMyButton)
}
would be nice if there was a way to completely ignore parts of the dom. like special portals or something.
@MattMcFarland not sure that's possible in a DOM-compliant way using the current version of morphdom :/ - maybe if we enumerate the issues we're currently facing with creating new components we might be able to come up with a better way to do this