Skip to content

Allow to pass observable as state keysΒ #91

@ApplY3D

Description

@ApplY3D

Which @ngneat/query-* package(s) are relevant/releated to the feature request?

No response

Description

If you use Tanstack Query in React world (useQuery(['posts', id], ()=>{})), state keys are being recalculated every id change together with data refetch.

@ngneat/query does not support this reactive recalculation. We should get new query for every new id:

import { UseQuery } from '@ngneat/query';

@Injectable({ providedIn: 'root' })
export class TodosService {
  private http = inject(HttpClient);
  private useQuery = inject(UseQuery);

  getTodo(id: number) {
    return this.useQuery(['todo', id], () => {
      return this.http.get<Todo>(
        `https://jsonplaceholder.typicode.com/todos/${id}`
      );
    });
  }
}

To provide reactive functionality, useQuery function should consume object with observable values and automatically refetch data on observable changes:

import { UseQuery } from '@ngneat/query';
import { Observable } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class TodosService {
  private http = inject(HttpClient);
  private useQuery = inject(UseQuery);

  getTodoById(id$: Observable<number>) {
    return this.useQuery(['todo', {id: $id}], ({ id }) => {
      return this.http.get<Todo>(
        `https://jsonplaceholder.typicode.com/todos/${id}`
      );
    });
  }
}

Then inside component:

@Component()
export class TodosPageComponent {
  id$ = new BehaviorSubject(1) // signal(1)
  todos$ = inject(TodosService).getTodoById(this.id$)
}

Proposed solution

Add way to pass observable as state key and get them inside http query.

Alternatives considered

https://github.com/liaoliao666/react-query-kit

import { createQuery } from 'react-query-kit'

type Response = { title: string; content: string }
type Variables = { id: number }

const usePost = createQuery<Response, Variables, Error>({
  primaryKey: '/posts',
  queryFn: ({ queryKey: [primaryKey, variables] }) => {
    // primaryKey equals to '/posts'
    return fetch(`${primaryKey}/${variables.id}`).then(res => res.json())
  },
  suspense: true
})

const variables: Variables = { id: 1 }
export default function Page() {
  // queryKey equals to ['/posts', { id: 1 }]
  const { data } = usePost({ variables, suspense: true })

  return (
    <div>
      <div>{data?.title}</div>
      <div>{data?.content}</div>
    </div>
  )
}

Do you want to create a pull request?

No

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions