25

I am currently building a Ruby on Rails Webpacker application with a React front end. I am at the point where I would like to create all the quires I need to make calls to my Rails API. I was loosely following this tutorial https://www.youtube.com/watch?v=0bKc_ch6MZY (https://github.com/daryanka/react-query-tutorial/blob/master/src/containers/Post.js, https://github.com/daryanka/react-query-tutorial/blob/master/src/Queries.js), in order to write some axios based query functions that I could use with react-query. I had no problem with getting the queries to behave as expected when the url for the endpoint was a hard coded string. When I attempted to pass in a parameter to make dynamic urls I ran into the issue of not having access to said parameter; specifically the "prodId" parameter. I did however notice that the "prodId" was inside the "key" parameter array like so:

queryKey: Array(2)
0: "product"
1: "1"
length: 2
enter code here

I could just access it from there but that approach does seem a little off, I also did not find any examples or documentation that attempted to access a parameter from the query key array. I would like to know what it is I am doing incorrectly with regards to passing in parameters? Were there some syntax changes in react-query that I am not taking into account?

react-query@^3.17.2

webpacker (5.2.1)

axios@^0.21.1

//Product.js

import axios from "axios"
import { getProduct } from "../../queries/products"
import { useQuery } from "react-query"

const prodId= '1'
const { data } = useQuery(['product', prodId], getProduct)

//queries/products.js
import axios from 'axios'

export const getProduct = async (key, { prodId }) => {
    console.log(opid)
    const { data } = await axios.get(`/api/v1/products/${prodId}`)
    return data
}
Nuno André
  • 4,739
  • 1
  • 33
  • 46
humbledev7000
  • 275
  • 1
  • 4
  • 8

2 Answers2

66

The query function that you pass to react-query gets a queryContext injected, which is an object that consists of the queryKey (and some more information if you are using an infinite query). So yes, one correct way to access dependencies is through the queryKey:

export const getProduct = async ({ queryKey }) => {
    const [_, prodId] = queryKey
    const { data } = await axios.get(`/api/v1/products/${prodId}`)
    return data
}
const { data } = useQuery(['product', prodId], getProduct)

Another way is to use inline anonymous functions, which is well documented in the docs in: If your query function depends on a variable, include it in your query key

export const getProduct = async (prodId) => {
    const { data } = await axios.get(`/api/v1/products/${prodId}`)
    return data
}
const { data } = useQuery(['product', prodId], () => getProduct(prodId))
Maxim Mazurok
  • 3,856
  • 2
  • 22
  • 37
TkDodo
  • 20,449
  • 3
  • 50
  • 65
  • 1
    I did actually give this approach a try after reading through the docs, I think in my flurry of iteration, I may not of had the correct query function parameter signature for the inline syntax. much thnaks. – humbledev7000 Jun 24 '21 at 13:23
  • how to pass query context along with `pageParam` parameter which is used to fetch next page in `useInfiniteQuery`? – KarthikNayak98 Jan 18 '22 at 16:16
  • it works exactly the same way. `pageParam` is just another field in the context that you can destruct like the `queryKey`,and it will be filled by react-query depending on what you return from `getNextPagePraam` – TkDodo Jan 19 '22 at 11:11
  • First off @TkDodo thanks for your responses! I've read a couple of your answers through SO and GH so much appreciated . What am I missing? This seems like a basic requirement for using async fns and this is overly complicated way to do it. – Sunny Patel Apr 14 '22 at 01:20
  • 1
    @SunnyPatel I don't know what you are missing - I don't even know what your question is ... – TkDodo Apr 15 '22 at 13:49
  • How is the second method used with the params object? Eg. `useQuery( ... , {onError:(error)=>{...}})` – Bersan Nov 17 '22 at 23:34
  • please how to use multiple parameters ? – VersifiXion Jan 14 '23 at 21:27
6

I'm using the following (typescript) to send parameters to my custom useQuery hook.

import { useQuery } from 'react-query'
import service from '../api'

const queryKey = 'my-query-key'
type useProductsParams = Parameters<typeof service.listProducts>

const useProducts = (...params: useProductsParams) => {
  return useQuery(queryKey, () => service.getProduct(...params))
}

export default useProducts
Gabriel Brito
  • 1,003
  • 2
  • 16
  • 26
  • 1
    Based on the documentation for `QueryKeys`, keys have to be an array. `From Docs`: Query keys have to be an Array at the top level, and can be as simple as an Array with a single string, or as complex as an array of many strings and nested objects. – MauricioLeal Apr 10 '23 at 17:39