Does Mithril 2.x Reset Component State When Key Changes Across Routes?
0 reputation · 06 Nov 2022, 18:43 UTC
0 reputation · 06 Nov 2022, 18:43 UTC
To understand how Mithril 2.x handles component lifecycle when the same component is rendered under different routes with distinct key attributes.
Mithril 2.x introduced a key property that signals the virtual DOM to treat a component instance as a new entity. When a component is rendered with a new key, the diffing algorithm detaches the old virtual node and mounts a fresh one, which triggers oncreate again. However, the framework documentation does not clarify whether internal component state (e.g., properties set in oninit or data bindings) is reset or preserved after a key change. In Mithril 1.x, the same component would not be re‑created on key change, leading to a compatibility gap for projects upgrading to 2.x.
Is the internal state of a component cleared automatically when its key changes, or does Mithril preserve it across route transitions?
key on a component that is reused across routes cause oncreate to fire again in all current 2.x releases?34775 reputation · 07 Nov 2022, 06:42 UTC
When a component is rendered with a new key, the virtual DOM diffing algorithm treats the resulting node as a completely different entity rather than an update to an existing one. This forces Mithril to detach the old virtual node and mount a fresh instance, effectively wiping any state tied to the previous instance.
The reset occurs during the reconciliation process. When the diffing algorithm identifies a key change at the same position in the DOM tree, it triggers a full lifecycle replacement rather than a patch. The sequence is as follows:
onDestroy.oninit.oncreate.Because the previous instance is discarded and eligible for garbage collection, any data stored in the component's closure or instance object is lost. This differs from Mithril 1.x, where components were often reused, potentially leading to state persistence across route transitions.
To confirm this behavior in a Mithril 2.x environment, implement a component with local state and navigate between routes using different keys:
const Counter = {
oninit: (vnode) => {
vnode.state = { count: 0 };
},
view: (vnode) => {
return m("div", [
m("p", `Count: ${vnode.state.count}`),
m("button", { onclick: () => vnode.state.count++ }, "Add")
]);
}
};
// Route config
m.route(document.body, "", {
"/user/1": () => m(Counter, { key: "user-1" }),
"/user/2": () => m(Counter, { key: "user-2" })
});
If you increment the counter on /user/1 and navigate to /user/2, the count will reset to 0.
This behavior applies specifically to component-local state. If state is stored in a global object, an external store, or a shared service, it will persist across key changes because those objects exist outside the Mithril component lifecycle. We assume the use of standard Mithril 2.x reconciliation logic.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.