luisherranz / deepsignal

DeepSignal 🧶 - Preact signals, but using regular JavaScript objects

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Update effect after change to any property of any element in array

fuf opened this issue · comments

Hi,

Thanks for the excellent library.

I think I'm missing something fundamental but is it possible to define an effect that will update after any change to an array of objects, and not just a specific property of one of the objects?

Here's an example of what I mean:

const state = deepSignal({
  myArray: [
    {
      count: 0,
    },
    {
      count: 0,
    },
  ],
});

const IncrementArray = () => {
  return (
    <Button onClick={() => state.myArray[0].count++}>Increment</Button>
  );
};

// Updates after increment
effect(() => {
  if (state.myArray[0].count) {
    console.log("state.myArray[0].count has changed");
  }
});

// Doesn't update after increment
effect(() => {
  if (state.myArray[0]) {
    console.log("state.myArray[0] has changed");
  }
});

// Also doesn't update after increment
effect(() => {
  if (state.myArray) {
    console.log("state.myArray has changed");
  }
});

Is there any way to write either of those last two effects so that they will trigger when any property changes for any element in the array?

I know I can get the second effect working by incrementing the count like this instead:

 <Button
        onClick={() =>
          (stateTest.myArray[0] = {
            ...stateTest.myArray[0],
            count: stateTest.myArray[0].count + 1,
          })
        }
      >
        Increment
      </Button>

But I am really loving the ability to modify the property directly that this library provides.

Thanks!

The only way to subscribe to a property is by accessing that property. So if you want to subscribe to all properties, you need to access all the properties.

You can do so with your custom recursive method, or by using something that already does that, like JSON.stringify:

const subscribeToAllProperties = (obj) => JSON.stringify(obj);

You need to do it every time to make sure that you also subscribe to the new properties and desubscribe to the deleted ones:

effect(() => {
  subscribeToAllProperties(state.myArray);
  console.log("state.myArray has changed");
});

There you go: https://stackblitz.com/edit/vitejs-vite-elfovs


I'm closing this as solved, but feel free to reopen if you need more help with this topic.