Allow to pass observable as state keys
ApplY3D opened this issue · comments
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
Persisted Query section?
Persisted Query section?
I think it's different. In this example https://github.com/ngneat/query/blob/main/packages/playground/src/app/pagination-page/pagination-page.component.ts you should subscribe on observable and pass it's value to persisted query, right?
But I'm talking about the fact that we do not need to subscribe, let the library do it for you.
It should be easier:
// transform this
page$.pipe(switchMap(page => useQuery(['page',page])))
// into this
useQuery(['page',page$])
@NetanelBasal Just out of curiosity, do you think this would be possible now? I think with if we used signals, or transform all option keys to a signal and use a more sophisticated equals
function for it this could be doable. 🤔
Do we really need it? Calling the exposed setOptions should be enough, no?
@luii I've added an updateOptions in next branch. You can test it if you have a real use case. I don't use it in my application.