[Bug] intermediate "effect" invocations during array changes with wrong values
rozek opened this issue · comments
Consider the following code:
import { effect } from '@preact/signals-core'
import { deepSignal } from 'deepsignal'
let hugo = deepSignal({
list:[1,2,3]
})
effect(() => { console.log('> hugo.list',JSON.stringify(hugo.list)) })
console.log('push'); hugo.list.push(4) // works as intended
console.log('pop'); hugo.list.pop() // -> [1,2,3,null] -> [1,2,3]
console.log('shift'); hugo.list.shift() // [2,2,3] > [2,3,3] > [2,3,null] > [2,3]
console.log('unshift'); hugo.list.unshift(1) // [2,3,3] > [2,2,3] > [1,2,3]
console.log('insert'); hugo.list.splice(2,0,2.5) // [1,2,3,3] > [1,2,2.5,3]
console.log('delete'); hugo.list.splice(2,1) // [1,2,3,3] > [1,2,3,null] > [1,2,3]
console.log('assign')
hugo.list = hugo.list.slice(0,2).concat(2.5,hugo.list.slice(2)) // reacts 2x
This code produces the following output:
> hugo.list [1,2,3]
push
> hugo.list [1,2,3,4]
pop
> hugo.list [1,2,3,null]
> hugo.list [1,2,3]
shift
> hugo.list [2,2,3]
> hugo.list [2,3,3]
> hugo.list [2,3,null]
> hugo.list [2,3]
unshift
> hugo.list [2,3,3]
> hugo.list [2,2,3]
> hugo.list [1,2,3]
insert
> hugo.list [1,2,3,3]
> hugo.list [1,2,2.5,3]
delete
> hugo.list [1,2,3,3]
> hugo.list [1,2,3,null]
> hugo.list [1,2,3]
assign
> hugo.list [1,2,2.5,3]
> hugo.list [1,2,2.5,3]
As you can see, the effect
callback is invoked far too often - and the intermediate calls often log wrong lists (at least "wrong" from a functional point of view, what we see here might reveal some unwanted implementation details)
@rozek, what was the reason to close this?
well, actually, it was my fault: by adding support for defineProperty
(which I need for some objects), I got some unwanted insight into how array methods such as unshift
etc. work. I solved this problem by batch
ing the implementation of these methods in order to get just one callback invocation instead of several.
Sorry for bothering you!
now I run into a problem where some properties of an observed object must not be proxied because invoking methods would otherwise throw "illegal invocation" exceptions. I already saw your pending pull request for "shallowing" objects but am still struggling to get it working...
I already saw your pending pull request for "shallowing" objects but am still struggling to get it working...
Oh, yes. I still need to figure out the API to make it compatible with the types, but the code is working.