mithril.js: Delegation to `vnode.state` for view methods break `vnode.state` assignment idiom

This was initially brought up by @pygy, but somehow flew right under the radar until recently… 😟

TL;DR: this no longer works, but will instead throw internal errors:

var Component = {
    oninit(vnode) { vnode.state = {counter: 1} }
    view(vnode) {
        return m("div", [
            m("div", ["Count: " + vnode.state.counter]),
            m("button", {onclick() { vnode.state.counter++ }}, "Increment")
        ])
    }
}

m.mount(document.body, m(Component))

Where @pygy and I changed to using vnode.state instead of vnode.tag as the source of truth for component hooks, that meant the previous idiom of assigning your initial state to vnode.state no longer works now, because the prototype that contains the view and other hooks is now lost.

We’ll have to document this as a breaking change in the changelog for v1.1, and we’ll likely have to edit the documentation accordingly to not write to vnode.state where applicable and to document vnode.state as read-only/volatile (since Mithril sets it on its own).

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 35 (35 by maintainers)

Most upvoted comments

@pygy You can lazily set it based on whether the relevant magic properties exist, without resorting to defineProperty. Just getting it out of the common path of no attribute hooks at all is good enough. 😉

Actually, here’s what’s broken in master: Replacing vnode.state in the view isn’t reflected in context of the corresponding post-view hook. oncreate and onupdate get the previous state instead.