Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add autoRefetch Option to useQuery for automatic stale entry refetching #49

Open
quiteeasy opened this issue May 27, 2024 · 9 comments · May be fixed by #97
Open

Add autoRefetch Option to useQuery for automatic stale entry refetching #49

quiteeasy opened this issue May 27, 2024 · 9 comments · May be fixed by #97
Labels
✨ feature request a new feature request

Comments

@quiteeasy
Copy link
Contributor

Add a boolean option, autoRefetch, to automatically refetch an entry when it becomes stale.

@posva
Copy link
Owner

posva commented May 27, 2024

Interesting. This could be useful as a plugin once more stuff is exposed. I see it as a dangerous default as it would spam the server very often

@quiteeasy
Copy link
Contributor Author

Adding this as an option would be useful, but I would not set it to true by default

Copy link
Owner

posva commented May 27, 2024

If it's added, it should be fully tree shakable too

@quiteeasy
Copy link
Contributor Author

Should we add an option to QueryPlugin or possibly another plugin (perhaps as a separate package) to enable autoRefetch across the app, while still allowing control through each individual useQuery options? This approach would ensure it is tree-shakable and maintains flexibility

@posva
Copy link
Owner

posva commented May 27, 2024

We will see later on but probably a different kind of plugin. I think a lot of other more critical features are still missing before this 😄

@posva posva added the ✨ feature request a new feature request label May 27, 2024
@ymansurozer
Copy link

Would love to see this because it enables a major use case (use useQuery instead of adding manual polling).

Copy link
Owner

posva commented Nov 4, 2024

This should be doable as a plugin if anybody wants to contribute to the repo. The delay plugin should help to get started

@ymansurozer
Copy link

Thanks @posva! I'm writing a plugin for this but got stuck at accessing entry.stale in the plugin. I keep getting a Cannot read properties of null (reading 'staleTime') error. Would you have any ides or can you nudge me in the right direction? 🙏🏽

Minimal Reproduction: https://stackblitz.com/edit/github-ruyqjq?file=colada%2FautoRefetch.ts

Plugin file:

// plugins/auto-refresh/src/index.ts
import type { PiniaColadaPlugin, UseQueryEntry } from '@pinia/colada'

export interface PiniaColadaAutoRefetchOptions {
  /**
   * Whether to enable auto refresh by default.
   * Can be overridden per query.
   * @default true
   */
  enabled?: boolean
}

/**
 * Plugin that automatically refreshes queries when they become stale
 */
export function PiniaColadaAutoRefetch(
  options: PiniaColadaAutoRefetchOptions = {},
): PiniaColadaPlugin {
  // Default to enabled
  const { enabled = true } = options

  return ({ queryCache, scope }) => {
    // Keep track of active entries and their timeouts
    const refreshTimeouts = new Map<UseQueryEntry, NodeJS.Timeout>()

    queryCache.$onAction(({ name, after, args }) => {
      if (name === 'create') {
        after((entry) => {
          // Skip if auto-refresh is disabled globally or for this query
          const queryEnabled = entry.options?.autoRefetch ?? enabled
          if (!queryEnabled) return

          scope.run(() => {
            console.log('>> Running', entry.key)

            watch(
              () => entry.stale,
              (stale) => {
                console.log('>> Stale', stale)
                if (stale) {
                  // Clear any existing timeout
                  const existingTimeout = refreshTimeouts.get(entry)
                  if (existingTimeout) {
                    clearTimeout(existingTimeout)
                  }

                  // Schedule a refresh
                  const timeout = setTimeout(() => {
                    if (entry.active) {
                      console.log('>> Refreshing stale query:', entry.key)
                      queryCache.fetch(entry)
                    }
                    refreshTimeouts.delete(entry)
                  }, 0)

                  refreshTimeouts.set(entry, timeout)
                }
              },
              { immediate: true },
            )
          })
        })
      }

      // Clean up timeouts when entry is removed
      if (name === 'remove') {
        console.log('>> Remove', args)
        const [entry] = args
        const timeout = refreshTimeouts.get(entry)
        if (timeout) {
          clearTimeout(timeout)
          refreshTimeouts.delete(entry)
        }
      }
    })
  }
}

// Add types for the new option
declare module '@pinia/colada' {
  interface UseQueryOptions {
    /**
     * Whether to automatically refresh this query when it becomes stale.
     * Requires the PiniaColadaAutoRefetch plugin.
     */
    autoRefetch?: boolean
  }
}

@posva
Copy link
Owner

posva commented Nov 6, 2024

You get that error because the entry doesn't have options yet, so it cannot fetch. options are set by useQuery() calls. It's not a reactive property, so you can't watch it anyway. I would go for the fetch action (among others), to add a refetch timeout

@ymansurozer ymansurozer linked a pull request Nov 7, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
✨ feature request a new feature request
Projects
Status: Todo
Development

Successfully merging a pull request may close this issue.

3 participants