lukemorales / query-key-factory

A library for creating typesafe standardized query keys, useful for cache management in @tanstack/query
https://www.npmjs.com/package/@lukemorales/query-key-factory
MIT License
1.16k stars 32 forks source link

Allow computed props in keys #Vue #42

Closed AlmarAubel closed 1 year ago

AlmarAubel commented 1 year ago

As a Vue user it would be really nice if I could use Computed props a key names See this example from tanstack query website ->

// Get the user
const { data: user } = useQuery({
  queryKey: ['user', email],
  queryFn: () => getUserByEmail(email.value),
})

const userId = computed(() => user.value?.id)
const enabled = computed(() => !!user.value?.id)

// Then get the user's projects
const { isIdle, data: projects } = useQuery({
  queryKey: ['projects', userId],
  queryFn: () => getProjectsByUser(userId.value),
  enabled, // The query will not execute until `enabled == true`
})

For example

export const todoQueries = createQueryKeys('todos', {
  getTodo: (todoId: Ref<string | undefined>) => ({
    queryKey: [todoId],
    queryFn: () => aanvraagApi.aanvraagGetHvv(todoId.value!)
  })
});

Give the following error on getTodo

TS2322: Type '(todoId: Ref<string | undefined>) => { queryKey: [Ref<string | undefined>]; queryFn: () => Promise<AxiosResponse<Result1OfManagementAPIAanvragenPublicHvvDto>>; }' is not assignable to type 'FactoryProperty | DynamicKey'. 
  Type '(todoId: Ref<string | undefined>) => { queryKey: [Ref<string | undefined>]; queryFn: () => Promise<AxiosResponse<Result1OfManagementAPIAanvragenPublicHvvDto>>; }' is not assignable to type 'DynamicKey'. 
      Type '{ queryKey: [Ref<string | undefined>]; queryFn: () => Promise<AxiosResponse<Result1OfManagementAPIAanvragenPublicHvvDto>>; }' is not assignable to type 'KeyTuple | QueryKeyRecord | DynamicQueryFactoryWithContextualQueriesSchema | DynamicQueryFactorySchema | DynamicKeySchemaWithContextualQueries'. 
        Type '{ queryKey: [Ref<string | undefined>]; queryFn: () => Promise<AxiosResponse<Result1OfManagementAPIAanvragenPublicHvvDto>>; }' is not assignable to type 'DynamicQueryFactorySchema'. 
          Type '{ queryKey: [Ref<string | undefined>]; queryFn: () => Promise<AxiosResponse<Result1OfManagementAPIAanvragenPublicHvvDto>>; }' is not assignable to type 'QueryKeyRecord'. 
            Types of property 'queryKey' are incompatible. 
              Type '[Ref<string | undefined>]' is not assignable to type 'readonly [ValidValue]'. 
                Type 'Ref<string | undefined>' is not assignable to type 'ValidValue'.
                  Type 'Ref<string | undefined>' is not assignable to type 'AnyObject'.
                    Index signature for type 'string' is missing in type 'Ref<string | undefined>'.

Currently I get an type error when I translate this example to the query key factory. https://tanstack.com/query/v4/docs/vue/guides/dependent-queries

lukemorales commented 1 year ago

@AlmarAubel thanks for raising this issue! I'm not familiar with the Vue API so I'm trying to understand its particularities on the example you've shared. What are the trade offs when defining queryKey: ['projects', userId] vs queryKey: ['projects', userId.value]

AlmarAubel commented 1 year ago

Yes I understand it's very specific for Vue. Vue uses a concept called reactivity where a variable can be wrapped by a reactive object var x= ref(1) when x is update x.value = 2 it will automatically rerender the virtual dom( or trigger other functions).

When I do userId.value it will unwrap the value an dloose the reactivity so when userId is updated it will not update the key. In vue-query it works fine. I understand that this library is framework agnostic. If I have some time left next week I will look how vue-query handles reactive var and look how it could be used to extend this framework.

In the example above the computed function return some kind of reactive var (but is read-only)

lukemorales commented 1 year ago

@AlmarAubel I'm preparing a new release that will support your use-case

lukemorales commented 1 year ago

@AlmarAubel version v1.1.0 has been released and should fix your issue!

AlmarAubel commented 1 year ago

Whoo thank you very much. Will try it out tomorrow!

AlmarAubel commented 1 year ago

Tested it this morning and the following example is working! Great work Full working example here -> https://github.com/AlmarAubel/vue-query-computed-support

const userId = ref<string>("")

const userQueries = createQueryKeys('users', {  
  detail: (userId: MaybeRef<string>) => ({
    queryKey: [userId],
    queryFn: () => getUser(unref(userId)),

  }),
});

var { data, isLoading, status } = useQuery({
  ...userQueries.detail(userId),
  enabled: computed((() => !!userId.value))
});