preactjs / signals

Manage state with style in every framework
https://preactjs.com/blog/introducing-signals/
MIT License
3.79k stars 93 forks source link

`effect` called when the initial value is set to the signal #306

Closed wmxmw closed 1 year ago

wmxmw commented 1 year ago

The effect is called even when the initial value is set to the signal (creating the signal). Consider this code:

const id = signal(0)
effect(() => {
  // logs 0
  console.log(id.value)
})

What if I want to save the data of the signal to database every time it changes excluding the first initial value?

For example, the data needs to be initialized with a value from database and persisted every time it changes. Say if the database operations are asynchronous, we have to first create the signal (with a default value) and then set to it, but the default value will trigger the effect resulting the default value being set to the database.

Is there any solution to this?

billybimbob commented 1 year ago

Based on my understanding of signals and effects, the passed in callback for the effect function has to run immediately in order to subscribe to the signals.

This act of subscribing then allows for the effect to retrigger whenever the subscribed signal changes.

For your specific example, a way to skip the database write is to have an if condition within the effect itself:

const id = signal(0)
effect(() => {
  const currentId = id.value; // subscribes signal changes
  if (currentId !== 0) {
    console.log(currentId);
  }
})
dghez commented 5 months ago

Any solution on this without injecting custom logic/behaviour? I mean, it's fine but kinda annoying sometimes, especially if you use it as state and you have the same effect on multiple files

XantreDev commented 5 months ago

You can use reaction from @preact-signals/utils or just copy paste the source code of it https://github.com/XantreDev/preact-signals/blob/51664990f52963cd9c196096b8b6d92057c93da1/packages/utils/src/lib/utils/reaction.ts#L94C1-L134C3