platform icon indicating copy to clipboard operation
platform copied to clipboard

Make deepSignal lazy

Open MillerSvt opened this issue 8 months ago • 6 comments

Which @ngrx/* package(s) are relevant/related to the feature request?

signals

Information

I would like to write a deepSignal that will allow access to input.required. But when trying to do this, an error occurs:

readonly entity = input.required<Entity>();
readonly deepEntity = toDeepSignal(this.entity);
Error: Input is required but no value is available yet.

It happens because toDeepSignal tries receive value synchronously. It wold be great to add flag to enforce lazy deepSignal.

Describe any alternatives/workarounds you're currently using

No response

I would be willing to submit a PR to fix this issue

  • [x] Yes
  • [ ] No

MillerSvt avatar Apr 10 '25 03:04 MillerSvt

would that help already: https://stackblitz.com/edit/github-ruoqvbvp?file=src%2Fmain.ts.

@Component({
  selector: 'app-child',
  template: `<p>{{deepPerson().address.street()}}</p>`,
})
export class ChildComponent {
  person = input.required<Person>();

  deepPerson = computed(() => deepComputed(this.person));
}

Btw, you don't have access to toDeepSignal.

rainerhahnekamp avatar Apr 19 '25 19:04 rainerhahnekamp

This solution triggers an unnecessary change detection. The whole sense of the "Deep Signal" concept is lost.

MillerSvt avatar Apr 21 '25 11:04 MillerSvt

This solution triggers an unnecessary change detection.

How that? Can you elaborate on that, please?

rainerhahnekamp avatar Apr 21 '25 11:04 rainerhahnekamp

When I add deepPerson.address.street() to a template, I expect that the template will only update if the value of the street signal changes. However, this solution allows the template to update for two reasons:

  1. If the person object changes.
  2. If the address.screen field within the person object changes.

Consequently, if the person changes to someone with the same address.street value, the template will update even though it shouldn't.

In real world case, for example in signal store entity, address.street value can only changed when whole person object recreated. So if address.street was changed, person signal also changed. Because of that, there is no sense to use deepComputed at all, because it is the same that just person().address.street.

I believe we can simplify our approach by omitting the check for a record. Instead, we should always return a Proxy object. If the value cannot be accessed, we should simply throw an error. Alternatively, if this modification could a breaking changes, we could introduce an option to omit that check.

MillerSvt avatar Apr 21 '25 11:04 MillerSvt

Somewhat related to this, I came up with a lazy DeepSignal implementation here to allow for accessing potentially undefined state. #4772

james-vista avatar May 12 '25 01:05 james-vista

👋 Quick heads up. We haven't forgotten about this. We need to make sure that the DeepSignal behaves like any computed, linkedSignal, etc. which depends on an InputSignal.

rainerhahnekamp avatar May 21 '25 16:05 rainerhahnekamp

https://github.com/ngrx/platform/issues/4749#issuecomment-2870481331

to allow for accessing potentially undefined state

Oooh, I wonder if this could help with https://github.com/ngrx/platform/issues/4847

maxime1992 avatar Jun 26 '25 16:06 maxime1992