Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(angular-query): fix NG0602 error #6966

Merged
merged 2 commits into from
Feb 25, 2024
Merged

Conversation

riccardoperra
Copy link
Contributor

@riccardoperra riccardoperra commented Feb 24, 2024

This pr fixes the NG0602 error while using angular-query.

Since the latest update, consuming the signals inside the templates caused to log the error.

Screenshot 2024-02-24 alle 15 13 25

Wrapping the effect inside the untracked function, in combination to runInInjectionContext at the top level (which is already present), seems resolving the issue without preventing the effect from running without registering dependencies. The effect as I understood must be executed whenever the defaultedOptionsSignal changes, therefore the behavior would remain unchanged.

I'm relatively new to Angular signals, I have much more experience using solid-js ones. Personally I would have solved it using nested effects but I think angular does not support them, like tracking dependencies after the first run 🤔

Also, I changed the Promise.resolve.then() using queueMicrotask. I think it is more suitable in this case. Is there a particular reason why Promise.resolve was used?

PS.
While debugging using the angular query examples, I had some troubles to get the updated code after building the library. I just had to disable the ng cache in order to let it work..I think this should be a default option for that repo examples

"cli": {
  "packageManager": "pnpm",
  "analytics": false,
  "cache": {
    "enabled": false
  }
},

@arnoud-dv

Copy link

vercel bot commented Feb 24, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

1 Ignored Deployment
Name Status Preview Comments Updated (UTC)
query ⬜️ Ignored (Inspect) Visit Preview Feb 25, 2024 0:27am

Copy link

codesandbox-ci bot commented Feb 24, 2024

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 8107437:

Sandbox Source
@tanstack/query-example-angular-basic Configuration
@tanstack/query-example-react-basic-typescript Configuration
@tanstack/query-example-solid-basic-typescript Configuration
@tanstack/query-example-svelte-basic Configuration
@tanstack/query-example-vue-basic Configuration

Copy link

nx-cloud bot commented Feb 25, 2024

☁️ Nx Cloud Report

CI is running/has finished running commands for commit 8107437. As they complete they will appear below. Click to see the status, the terminal output, and the build insights.

📂 See all runs for this CI Pipeline Execution


✅ Successfully ran 2 targets

Sent with 💌 from NxCloud.

@arnoud-dv
Copy link
Collaborator

arnoud-dv commented Feb 25, 2024

Thank you @riccardoperra !

Personally I would have solved it using nested effects but I think angular does not support them, like tracking dependencies after the first run 🤔

Did not look into it more than this video but nested effects should work in Angular. Although I'm not sure this could offer a solution as an effect is scheduled too late probably. I am interested in how you would solve it.

What is your opinion on the lazy init proxy? Last week I was working a few evenings on replacing it with more computed() signals but it would require unpure computed signals and not sure if that would be better than the proxy. I would love to brainstorm about this with someone with good insight in signals.

Also, I changed the Promise.resolve.then() using queueMicrotask. I think it is more suitable in this case. Is there a particular reason why Promise.resolve was used?

Not really, good call to use queueMicrotask instead.

I just had to disable the ng cache in order to let it work..I think this should be a default option for that repo examples

Agree, ran into this too.

@arnoud-dv arnoud-dv merged commit 3de4859 into TanStack:main Feb 25, 2024
4 checks passed
@riccardoperra
Copy link
Contributor Author

riccardoperra commented Feb 25, 2024

Did not look into it more than this video but nested effects should work in Angular. Although I'm not sure this could offer a solution as an effect is scheduled too late probably. I am interested in how you would solve it.

In that case I usually create an effect immediately that listen for an init signal, then schedule another effect only once the init signal is valued.

Did some test yesterday but probably I was doing something wrong. Today I managed to do it using untracked + injector property, but it doesn't seem to different to the current solution

    // could be a boolean, or maybe a function to call lazily which uses signals internally
    const ready = signal<boolean>(false);
    const injector = inject(Injector);
    const initEffect = effect(() => {
      const isReady = ready();
      if (!isReady) {
        return;
      }
      // destroying the init effect in order to be sure it's immediately
      // disposed after the first time
      initEffect.destroy();
      untracked(() =>
        effect(
          () => {
            // call something that will use signals, input signals etc.
          },
          // we need to pass injector because we are outside the "constructor" phase
          { injector }
        )
      );
    });

    queueMicrotask(() => ready.set(true));

What is your opinion on the lazy init proxy? Last week I was working a few evenings on replacing it with more computed() signals but it would require unpure computed signals and not sure if that would be better than the proxy. I would love to brainstorm about this with someone with good insight in signals.

Unlike other frameworks, inputs are not immediately available. Unpure computeds are a bad practice, using that lazy init with a proxy could be a great option, I can't think of any other solutions that doesn’t prevent errors..even if there are some particular cases that don't convince me.

  • Using required inputs, If I try to do something with my query result inside the constructor, the error will be thrown immediately
  postId = input.required<number>();

  postQuery = injectQuery(() => ({
    queryKey: ['post', this.postId()],
    queryFn: () => ...
  }))


  constructor() {
      console.log(this.postQuery.data());
  }
Screenshot 2024-02-25 alle 09 20 08
  • If i try to do something in the constructor using inputs (both signal or by decorator) with default value, the fn will schedule immediately with "wrong" values, since they are not available yet. I don't know if this is a problem but the devtools is tracking the query result
image

It therefore occurs to me that the result of the query is not directly accessible from the constructor, but must necessarily be executed in a reactive context such as an effect, or after onInit. So regardless we should prevent the access in this case...after all, those who develop in Angular know that certain things cannot be done in the constructor, especially if it uses inputs.

return new Proxy<T>({} as T, {
    get(_, prop, receiver) {
      if (!initialized) {
        // throw some understable error
      }
      // do something
    },
}

EDIT: this probably can't work anyway, because if the query is created inside the onInit there is a risk that the value will be inaccessible anyway. It's not possible to intercept the time after the constructor but before the template execution I think

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants