Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

Sorry, you do not have permission to ask a question, You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please type your username.

Please type your E-Mail.

Please choose an appropriate title for the post.

Please choose the appropriate section so your post can be easily searched.

Please choose suitable Keywords Ex: post, video.

Browse

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise Logo Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise Logo

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise Navigation

  • Home
  • About Us
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • About Us
  • Contact Us
Home/ Questions/Q 1273

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise Latest Questions

Author
  • 62k
Author
Asked: November 25, 20242024-11-25T06:36:08+00:00 2024-11-25T06:36:08+00:00

TanStack Query: Angular/React differences

  • 62k

As I have been trying to learn Angular Query, I discovered that there is not a lot of documentation on it yet, even though it is an amazing framework. Consequently, I have been going through a lot of React Query tutorials to try to learn its best practices and bring those over to how I use Angular Query. Some of these differences, however, are not obvious, and have tripped me up. Hopefully this list will help you out until there are more tutorials and examples specific to Angular.

Differences

1. injectQuery in any injection context

In React, useQuery follows the Rules of hooks, namely that there are specific places where useQuery can be called, and it cannot be called anywhere else.
In Angular Query, injectQuery does not have that limitation. Under normal circumstances, we can inject it whenever we are inside an injection context. Here are some examples where it would work:

Class variables and constructors

@Component({   standalone: true,   templateUrl: './bulbasaur.component.html', }) export class BulbasaurComponent {   private readonly http = inject(HttpClient);    // 👍   readonly bulbasaurQuery = injectQuery(() => ({     queryKey: ['bulbasaur'],     queryFn: () =>       lastValueFrom(         this.http.get<PokeData>(           'https://pokeapi.co/api/v2/pokemon/bulbasaur'         ),       ),   }));    constructor() {     // 👍     const mewQuery = injectQuery(() => ({       queryKey: ['mew'],       queryFn: () =>         lastValueFrom(           this.http.get<PokeData>(             'https://pokeapi.co/api/v2/pokemon/mew'           ),         ),       })     );   } } 
Enter fullscreen mode Exit fullscreen mode

Anywhere the library author says

NgRx signal store features are run in an injection context. Here is how to use a query inside a signals store:

type PokeId = 'bulbasaur' | 'ivysaur' | 'venusaur'; type PokeData = {...};  interface PokemonState {   pokeId: PokeId; }  const initialState: PokemonState = {   pokeId: 'bulbasaur', };  const PokemonStore = signalStore(   withState(initialState),   withComputed((store) => {     const http = inject(HttpClient);     const { status, data } = injectQuery(() => ({       queryKey: ['pokemon', store.pokeId()],       queryFn: () =>         lastValueFrom(           http.get<PokeData>(             `https://pokeapi.co/api/v2/pokemon/${store.pokeId()}`           ),         ),     }));      return { status, data };   }),   withMethods((store) => ({     setPokeId: (pokeId: PokeId) => patchState(store, { pokeId }),   })), ); 
Enter fullscreen mode Exit fullscreen mode

Anywhere else

Route guards (don't do it), resolvers, or anywhere if we include the current Injector:

@Component({   standalone: true,   templateUrl: './poke-prefetch.component.html', }) export class PokemenComponent {   private readonly http = inject(HttpClient);   private readonly injector = inject(Injector);    // https://bulbapedia.bulbagarden.net/wiki/Category:Male-only_Pok%C3%A9mon   pokemen = [     'nidoran♂',     'nidoking',     'hitmonlee',     'hitmonchan',     'tauros',   ] as const;    async prefetchPokemen() {     const queryClient = injectQueryClient({ injector: this.injector });      await Promise.all(       this.pokemen.map((pokeman) => {         return queryClient.prefetchQuery({           queryKey: ['pokemon', pokeman],           queryFn: () =>             lastValueFrom(               this.http.get<PokeData>(                 `https://pokeapi.co/api/v2/pokemon/${pokeman}`,               ),             ),         });       }),     );   } } 
Enter fullscreen mode Exit fullscreen mode

2. useQuery({...}) versus injectQuery(() => {...})

This is the reason for this article. I messed this up so many times when I first started. The first parameter of injectQuery is a function, not an object. But why?
It does not say anything about this in Angular Query's documentation, but it does in Solid Query:

Arguments to solid-query primitives (like createQuery, createMutation, useIsFetching) listed above are functions, so that they can be tracked in a reactive scope.

I don't know what a reactive scope is, so maybe not 😒

Just remember that injectQuery's first parameter is a function and you'll be good to go.

3. Angular gets queryClient for free

injectQuery's first parameter actually passes queryClient as its first parameter:

//                            👇👇 const query = injectQuery((queryClient) => ({   queryKey, queryFn })); 
Enter fullscreen mode Exit fullscreen mode

I have found this very useful with injectMutation and optimistic updates.

// No need to also add injectQueryClient()  const mutation = injectMutation((queryClient) => ({   mutationFn: (updates) => this.service.updateThing(updates),   onMutate: async (updates) => {     await queryClient.cancelQueries({ queryKey });      const snapshot = queryClient.getQueryData(queryKey);      queryClient.setQueryData(queryKey, (prev) =>       prev.filter((p) => p.id !== updates.id),     );      return snapshot;   },   onError: (_error, _variables, snapshot) => {     queryClient.setQueryData(queryKey, snapshot);   },   onSettled: () => {     return queryClient.invalidateQueries({ queryKey });   }, })); 
Enter fullscreen mode Exit fullscreen mode

4. Superfluous differences

These may not even be worth mentioning, but here goes.

  • React is use* and Angular is inject*
  • Angular uses signals. To access data or any of the fields of the query object, add () to the end of it
// React const MyComponent = () => {   const { data } = useQuery({ queryKey, queryFn });    return <p>{ data ?? '😬' }</p>; };  // Angular @Component({   standalone: true, //       👇   template: `<p>{{ query.data() ?? '😬' }}</p>`, }) //                        👆 class MyComponent {   query = injectQuery({ queryKey, queryFn }); } 
Enter fullscreen mode Exit fullscreen mode

Notes

I use injectQuery in all of the examples, but everything applies to injectMutation, too. Once injectQueries is ready, these will hopefully apply there, too.

Conclusion

That's it! Thanks for reading and I hope you learned something! Let me know if I missed anything.

angularfrontendtypescriptwebdev
  • 0 0 Answers
  • 1 View
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

Sidebar

Ask A Question

Stats

  • Questions 4k
  • Answers 0
  • Best Answers 0
  • Users 2k
  • Popular
  • Answers
  • Author

    ES6 - A beginners guide - Template Literals

    • 0 Answers
  • Author

    Understanding Higher Order Functions in JavaScript.

    • 0 Answers
  • Author

    Build a custom video chat app with Daily and Vue.js

    • 0 Answers

Top Members

Samantha Carter

Samantha Carter

  • 0 Questions
  • 20 Points
Begginer
Ella Lewis

Ella Lewis

  • 0 Questions
  • 20 Points
Begginer
Isaac Anderson

Isaac Anderson

  • 0 Questions
  • 20 Points
Begginer

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help

Footer

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise

Querify Question Shop: Explore, ask, and connect. Join our vibrant Q&A community today!

About Us

  • About Us
  • Contact Us
  • All Users

Legal Stuff

  • Terms of Use
  • Privacy Policy
  • Cookie Policy

Help

  • Knowledge Base
  • Support

Follow

© 2022 Querify Question. All Rights Reserved

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.