最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Computed signal dependencies - Stack Overflow

programmeradmin2浏览0评论

Question to the Angular experts about Signals:

When you create a puted() signal, dependencies are automatically tracked, but according to the docs only for signals that were previously read.

If I understand this correctly, would the following be problematic since the every could potentially shortcircuit if the one of the first items is not selected, making the puted function only track a subset of the items?

const allSelected = puted(() => {     
    return selectableItems.every(item => item.selected()); 
});

To be clear: item.selected() is a signal as well.

It seems to be running fine, but I want to be sure.

Question to the Angular experts about Signals:

When you create a puted() signal, dependencies are automatically tracked, but according to the docs only for signals that were previously read.

If I understand this correctly, would the following be problematic since the every could potentially shortcircuit if the one of the first items is not selected, making the puted function only track a subset of the items?

const allSelected = puted(() => {     
    return selectableItems.every(item => item.selected()); 
});

To be clear: item.selected() is a signal as well.

It seems to be running fine, but I want to be sure.

Share Improve this question asked Nov 27, 2023 at 9:16 user1337157user1337157 811 silver badge6 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 6

Your particular issue of concern shouldn't be an issue. For selectableItems to be true all items will have to be evaluated. If an item turns to false, it doesn't matter if an item with a greater index bees false in the future because logically the result of every will still be the same.

That being said, you will have issues if selectableItems can have items added or removed.

An extreme example is if selectableItems is empty when puted is called. At that point, no signals will fire and the value will never be checked again.

A less extreme issue would be if an item is added at a later point. The value of allSelected won't be evaluated until one of the previous items have their value changed. If all the old items are true and the new item is false, then allSelected will be wrong.

If selectableItems can change, then a better design might be to make selectableItems a signal instead of all the individual items, and then use update when an item is changed.

// changed selectableItems to items to make example shorter.
items = signal([] as SelectableItem[]);

const allSelected = puted(() => this.items().every(item => item.selected));
addItem(item: SelectableItem) {
  this.items.update(x => [...x, item]);
}
updateItem(item: SelectableItem) {
  this.items.update(x => {
    const index = x.indexOf(item);
    return [...x.slice(0, index), item, ...x.slice(index + 1, 0)];
  });
}

Advanced Solution

If you wanted to keep the logic of your array outside of your ponent you could even create your own signal. The solution below adds methods to a writable signal and uses undocumented but exported functions from core signal primitives.

export interface ArraySignal<T> extends WritableSignal<T[]> {
  updateElement(item: T, updateFn: (x: T) => T): void;
  push(item: T): void;
}

export function arraySignal<T>(initialValue: T[]): ArraySignal<T> {
  const internal = signal(initialValue) as SignalGetter<T[]> & WritableSignal<T[]>;
  const node = internal[SIGNAL];
  return Object.assign(internal, {
    push: (item: T) => signalMutateFn(node, (x) => {
      x.push(item);
      return x;
    }),
    updateElement: (item: T, updateFn: (x: T) => T) => {
      signalMutateFn(node, (x) => {
        const index = x.indexOf(item);
        (index !== -1) && (x[index] = updateFn(item));
      })
    }
  })
}
发布评论

评论列表(0)

  1. 暂无评论