Why no diff for arrays? #71
Replies: 3 comments
-
Thanks for the comments! It's a feature we would like to consider in the future, although it's not among the feature list of the 1.0.0 release. The feature probably needs a thorough and thoughtful design to make the implementation right. It might not be easy to have a well-rounded solution while keeping VanJS lightweight. |
Beta Was this translation helpful? Give feedback.
-
In my past practical experience. It is possible to find the smallest difference.(with unique key) But while operating the dom, it becomes difficult. There will be some situations here, such as deletion, addition, and movement. As a library's code grows, its behavior becomes more complex. I don't think it's a good idea to add array diff to vanjs. On the other hand, when I use van-jsx, it does bring me a little inconvenience that I cannot directly use array as children. What I want to do is create a function
The lazyDiff will be execute at here.So that vanjs can collect it deps. Then the lazyDiff subscribe the arrayState, if the state change. lazyDiff do the array diff. And call |
Beta Was this translation helpful? Give feedback.
-
@zhangzheheng12345 Here is a solution. You can implement your array diff algorithm in the comment, perhaps using the "edit distance". For this example https://vanjs.org/demo#todo-app class TodoItemState {
constructor(public text: string, public done: State<boolean>, public deleted: State<boolean>) {}
serialize() { return {text: this.text, done: this.done.val} }
}
const TodoItem = ({text, done, deleted}: TodoItemState) => () => deleted.val ? null : div(
input({type: "checkbox", checked: done, onclick: e => done.val = e.target.checked}),
() => (done.val ? strike : span)(text),
a({onclick: () => deleted.val = true}, "❌"),
)
class TodoListState {
private constructor(public todos: TodoItemState[]) {}
save() {
localStorage.setItem("appState", JSON.stringify(
(this.todos = this.todos.filter(t => !t.deleted.val)).map(t => t.serialize())))
}
static readonly load = () => new TodoListState(
JSON.parse(localStorage.getItem("appState") ?? "[]")
.map((t: any) => new TodoItemState(t.text, van.state(t.done), van.state(false)))
)
add(text: string) {
this.todos.push(new TodoItemState(text, van.state(false), van.state(false)))
return new TodoListState(this.todos)
}
}
const TodoList = () => {
const appState = van.state(TodoListState.load())
van.derive(() => appState.val.save())
const inputDom = input({type: "text"})
return div(
inputDom, button({onclick: () => appState.val = appState.val.add(inputDom.value)}, "Add"),
(dom?: Element) => {
// Do some array diff here, may be use "Edit Distance"
if (!dom) return div(appState.val.todos.map(TodoItem))
return van.add(dom, TodoItem(appState.val.todos.at(-1)!))
}
)
} |
Beta Was this translation helpful? Give feedback.
-
Imagine a situation: there's an array constructed from
van.state([])
, which has contained plenty of items, and which has been iterated to build a list of HTML elements. And each of these elements has a few sons and grandsons. It's quite wasteful to reload all these elements for the change of only one value in the array.I don't mean virtual DOM; I hate it myself. Just like what Solid does, a utility can be provided, which uses a diff algorithm to optimize the updates of the list (in Solid that's
<For>
, and in VanJS it might beiter()
or something). Yes often you won't need it, for example when the array is small, and when there are too many changes to have diff hold its superiority. But it's optional. BTW you might say they can be reloaded, inserted or deleted straight away. Yet that loses the spirit of relativity; why don't you use jQuery and its substitutes then?As for the size, I think it doesn't matter. Only a light and fast algorithm is required, which needn't be precise. Just to reduce the steps of updating.VanJS will stay light, and meanwhile gain higher performance, won't it?
Beta Was this translation helpful? Give feedback.
All reactions