wolfram77
wolfram77

Reputation: 3221

Why does m.render() not update view when i remove elements from begining?

Here, i am trying to update the document to contain a number of elements, and i am removing the step by step. I have tried 2 approaches, one which does not involve creating m-objects, and another one where i create new m-objects on every m.render(). I was using the first method in my program, and it didnt work, so i decided to test Mithril and found this behaviour.

This does not work:

e1 = m('i', 'e1');
e2 = m('i', 'e2');
e3 = m('i', 'e3');
m.render(document.body, m('b', [e1, e2, e3]));
// "e1e2e3" appears
m.render(document.body, m('b', [e2, e3]));
// "e2e3" appears
m.render(document.body, m('b', [e3]));
// "e2e3" appears
m.render(document.body, m('b', []));
// "e2e3" appears

Interestingly, if instead i remove items from the end, it works:

e1 = m('i', 'e1');
e2 = m('i', 'e2');
e3 = m('i', 'e3');
m.render(document.body, m('b', [e1, e2, e3]));
// "e1e2e3" appears
m.render(document.body, m('b', [e1, e2]));
// "e1e2" appears
m.render(document.body, m('b', [e1]));
// "e1" appears
m.render(document.body, m('b', []));
// "" appears

And, this method always works (both ways):

m.render(document.body, m('b', [m('i', 'e1'), m('i', 'e2'), m('i', 'e3')]));
// "e1e2e3" appears
m.render(document.body, m('b', [m('i', 'e2'), m('i', 'e3')]));
// "e2e3" appears
m.render(document.body, m('b', [m('i', 'e3')]));
// "e3" appears
m.render(document.body, m('b', []));
// "" appears

I think i could use the last method in my program, but i wanted to know why the original method does not work.

Upvotes: 0

Views: 104

Answers (1)

ArneHugo
ArneHugo

Reputation: 6509

Use keys: https://mithril.js.org/keys.html

When you are working with lists of data that may change (reorder or add/remove items) it's good practice to set a key to each component/element that is related to the data it presents.

I am not exactly sure what Mithril does under the hood here, but without the keys it's not able to properly identify which children are being removed every time. (It more often works when removing from the end of the list.)

With proper keys, however, it always works:

var children = [
    m('i', {key: 'e1'}, 'e1'),
    m('i', {key: 'e2'}, 'e2'),
    m('i', {key: 'e3'}, 'e3')
];

function show() {
    m.render(document.body, m('b', {onclick: removeFirst}, children));
}

function removeFirst() {
    children = children.slice(1);
    console.log('children', children);
    show();
}

show();
<body>
    <script src="https://unpkg.com/mithril/mithril.js"></script>
    <script src="index.js"></script>
</body>

Upvotes: 2

Related Questions