luisherranz / deepsignal

DeepSignal 🧶 - Preact signals, but using regular JavaScript objects

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[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 batching 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.