justin-schroeder / arrow-js

Reactivity without the framework

Home Page:https://arrow-js.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Keyed lists causing re-render

Grafikart opened this issue · comments

I have just tried the library and it's quite impressive for a such small code but I'm having an issue with list and map. We can use .key() to avoid creating new item but the problem happens when we use

  return t`
      <ul>
        ${() => state.todos.map((todo) => TodoItem(todo).key(todo.id) )}
      </ul>
  `;

The problem with this loop, it will rerender every list item even if we only edit one element todos[1].title for instance.

Expectation

The system could proxy the map méthod to "memo" the value and only rerun the method when the item in the array changed.

This depends on how your TodoItem is structured. If it renders its props also using arrow fns, those should be isolating boundaries preventing the list from re-rendering.

It is still quite experimental however so if it’s not actually doing that properly it wouldn’t be a huge shock, are you able to provide a reproduction?

Here is an example of the problem (I just kept the code linked to the issue)

import { r, t} from "@arrow-js/core";

const root = document.querySelector("#root");
const endpoint = "http://jsonplaceholder.typicode.com/todos?_limit=10";

const TodoItem = (todo) => {
  return t`<li>
    <span>${() => todo.title}</span>
    <input type="text" name="title" value="${todo.title}" @input="${(e) => todo.title = e.currentTarget.value}">
  </li> `;
};

const TodoList = () => {
  const state = r({
    loading: true,
    todos: [],
  })

  fetch(endpoint).then(r => r.json()).then(todos => {
    state.loading = false
    state.todos = todos
  })

  return t`
    <div>
      ${() => state.loading && t`<div>Chargement...</div>`}
      <ul>
        ${() => state.todos.map((todo) => TodoItem(todo).key(todo.id))}
      </ul>
    </div>
  `;
};

TodoList()(root);

I created a CodeSandbox https://codesandbox.io/s/arrow-js-list-hej0sn?file=/src/index.js to illustrate the problem. When I input a letter in an input, the whole list is rerendered and we loose the focus.

Hmm..interesting. It seems this is related to using keys specifically — If I remove the keys, all good:

https://codesandbox.io/s/arrow-js-list-forked-vimmge?file=/src/index.js