Skip to content

[WIP] New useQueryState Hook #5

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

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open

[WIP] New useQueryState Hook #5

wants to merge 9 commits into from

Conversation

arvi18
Copy link

@arvi18 arvi18 commented Apr 23, 2025

Closes TanStack#6756

TODO:

  • Fix any broken tests
  • Migrate useQueryState logic to useMutationState
  • Add working tests for useQueryState
  • Mark useIsFetching as deprecated
  • Mark useIsMutating as deprecated
  • Update docs to note deprecated fields
  • Add reference docs

Summary by CodeRabbit

  • New Features

    • Introduced a new hook that allows reactive access to query states with customizable filtering and selection.
    • Added public export for the new query state hook, making it available for use in applications.
  • Refactor

    • Simplified the implementation of existing hooks for fetching and mutation state, improving performance and maintainability.
  • Tests

    • Updated tests to enhance component memoization and adjust hook usage order for improved reliability and efficiency.

@arvi18
Copy link
Author

arvi18 commented Apr 23, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

1 Ignored Deployment
Name Status Preview Comments Updated (UTC)
query ⬜️ Ignored (Inspect) Visit Preview Feb 3, 2024 11:23am

@arvi18
Copy link
Author

arvi18 commented Apr 23, 2025

☁️ Nx Cloud Report

CI is running/has finished running commands for commit 05e18d3. As they complete they will appear below. Click to see the status, the terminal output, and the build insights.

📂 See all runs for this CI Pipeline Execution


✅ Successfully ran 1 target

Sent with 💌 from NxCloud.

@arvi18
Copy link
Author

arvi18 commented Apr 23, 2025

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 05e18d3:

Sandbox Source
@tanstack/query-example-angular-basic Configuration
@tanstack/query-example-react-basic-typescript Configuration
@tanstack/query-example-solid-basic-typescript Configuration
@tanstack/query-example-svelte-basic Configuration
@tanstack/query-example-vue-basic Configuration

@arvi18
Copy link
Author

arvi18 commented Apr 23, 2025

There appear to be two failing tests on this PR and I can't seem to figure out why they're failing. Namely, they are the useFetching API that's been changed.

While debugging, I've noticed the following:

  • notifyManager.schedule(onStoreChange) in useQueryState is called properly with the single item
  • onStoreChange is not ever called

I can't seem to figure out why this is the case or why it works in the other tests, but not these.

It also appears that there's some timing issues with sleep(10) that I've resolved by replacing with new Promise changes.

@arvi18
Copy link
Author

arvi18 commented Apr 23, 2025

Codecov Report

Attention: 2 lines in your changes are missing coverage. Please review.

Comparison is base (c190f68) 41.78% compared to head (05e18d3) 85.09%.

Files Patch % Lines
packages/react-query/src/useQueryState.ts 90.00% 2 Missing ⚠️

❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@             Coverage Diff             @@
##             main    #6758       +/-   ##
===========================================
+ Coverage   41.78%   85.09%   +43.30%     
===========================================
  Files         178       24      -154     
  Lines        7017      322     -6695     
  Branches     1421       83     -1338     
===========================================
- Hits         2932      274     -2658     
+ Misses       3722       39     -3683     
+ Partials      363        9      -354     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link

coderabbitai bot commented Apr 23, 2025

Walkthrough

The changes introduce a new React hook, useQueryState, for accessing the state of queries in a reactive manner. The useIsFetching hook is refactored to use useQueryState instead of directly subscribing to the query cache. The useMutationState hook's subscription logic is simplified by shifting result comparison and update logic from the subscription callback to the snapshot getter. Test cases for useIsFetching and useIsMutating are updated to adjust hook call order and to use React.memo for components, respectively. The main export file is updated to include useQueryState.

Changes

File(s) Change Summary
packages/react-query/src/useQueryState.ts Introduced new hook useQueryState for reactive access to query states with filtering and selection options.
packages/react-query/src/useIsFetching.ts Refactored to use useQueryState for fetching count, removing manual subscription and sync external store use.
packages/react-query/src/useMutationState.ts Simplified subscription logic; moved result update logic from subscription callback to snapshot getter.
packages/react-query/src/index.ts Added export for useQueryState.
packages/react-query/src/__tests__/useIsFetching.test.tsx Moved useIsFetching hook call before useQuery in the test component.
packages/react-query/src/__tests__/useMutationState.test.tsx Wrapped IsMutating component in React.memo and renamed base function for improved test behavior.

Sequence Diagram(s)

sequenceDiagram
  participant Component
  participant useQueryState
  participant QueryClient
  participant QueryCache

  Component->>useQueryState: Call with options, queryClient?
  useQueryState->>QueryClient: Get QueryCache
  useQueryState->>QueryCache: Subscribe to updates
  QueryCache-->>useQueryState: Notify on change
  useQueryState->>Component: Return filtered query states (reactively)
Loading
sequenceDiagram
  participant Component
  participant useIsFetching
  participant useQueryState

  Component->>useIsFetching: Call with filters, queryClient?
  useIsFetching->>useQueryState: Call with filters + fetchStatus: 'fetching'
  useQueryState-->>useIsFetching: Return array of fetching queries
  useIsFetching->>Component: Return length of array (number of fetching)
Loading

Poem

In burrows deep, the queries run,
With hooks anew, the work is done.
State flows swift, like streams at night,
Memoized and counted right.
Exports grow, the garden thrives,
Reacting fast, our code survives.
🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4a5990e and 05e18d3.

📒 Files selected for processing (6)
  • packages/react-query/src/__tests__/useIsFetching.test.tsx (1 hunks)
  • packages/react-query/src/__tests__/useMutationState.test.tsx (3 hunks)
  • packages/react-query/src/index.ts (1 hunks)
  • packages/react-query/src/useIsFetching.ts (1 hunks)
  • packages/react-query/src/useMutationState.ts (1 hunks)
  • packages/react-query/src/useQueryState.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/react-query/src/__tests__/useMutationState.test.tsx (2)
packages/query-core/src/queryClient.ts (1)
  • isMutating (107-109)
packages/react-query/src/useMutationState.ts (1)
  • useIsMutating (15-24)
🪛 GitHub Actions: pr
packages/react-query/src/useQueryState.ts

[error] 39-39: TypeScript error TS2554: Expected 1 arguments, but got 0.

🔇 Additional comments (9)
packages/react-query/src/useQueryState.ts (1)

48-66:

❓ Verification inconclusive

Consider adding retry logic for failed query cache subscriptions

The PR objectives mention failing tests related to useFetching which relied on notifyManager.schedule(onStoreChange) callbacks not being invoked. Your implementation correctly uses notifyManager.batchCalls for performance, but might benefit from additional error handling.

Verify that the batch calls mechanism is robust in all edge cases by running this test:


🏁 Script executed:

#!/bin/bash
# Search for existing tests that verify batch call reliability
rg -A 5 "batchCalls" packages/react-query/src/__tests__/ packages/query-core/src/__tests__/

Length of output: 166


🏁 Script executed:

#!/bin/bash
# Search for 'batchCalls' across all test files in the repository
rg --with-filename --line-number "batchCalls" \
  --glob="*__tests__/**" \
  --glob="*.test.*" \
  --glob="*.spec.*"

Length of output: 212


🏁 Script executed:

#!/bin/bash
# Retrieve the implementation of batchCalls in notifyManager
rg --with-filename --line-number -A 20 "batchCalls" packages/query-core/src

Length of output: 2713


🏁 Script executed:

#!/bin/bash
# Show schedule and its related functions in notifyManager.ts
sed -n '1,120p' packages/query-core/src/notifyManager.ts

Length of output: 2473


Add error handling around batched subscriber callbacks

The PR objectives noted that useFetching tests were failing because notifyManager.schedule(onStoreChange) callbacks weren’t firing. You’ve correctly switched to using notifyManager.batchCalls(onStoreChange) for performance, but any exception thrown by a subscriber today will bubble up and abort the remaining notification pipeline (and won’t retry).

I located basic tests for batchCalls here:

  • packages/query-core/src/tests/notifyManager.test.tsx

However, they don’t cover error or retry scenarios. Please consider:

  • Wrapping the callback(...args) inside batchCalls with a try/catch so one failing subscriber can’t stop others.
  • Optionally introducing retry logic or logging for callbacks that throw.
  • Adding corresponding failure‐scenario tests in packages/query-core/src/tests/notifyManager.test.tsx.

Location to update:

  • packages/react-query/src/useQueryState.ts (lines 48–66): subscription via notifyManager.batchCalls(onStoreChange)
packages/react-query/src/index.ts (1)

43-43: LGTM! Properly exporting the new hook

The new useQueryState hook is correctly exported, making it available as part of the public API.

packages/react-query/src/__tests__/useIsFetching.test.tsx (1)

208-209: LGTM! Appropriate hook ordering

Moving the useIsFetching call before useQuery is a good practice and aligns with the refactored implementation that uses the new useQueryState hook.

packages/react-query/src/__tests__/useMutationState.test.tsx (2)

69-76: Good performance optimization with memoization

Using React.memo to prevent unnecessary re-renders from other mutation hooks is a good practice that improves test reliability and better reflects real-world component behavior.


110-119: LGTM! Consistent memoization pattern applied

The same memoization pattern is consistently applied here, which will improve test reliability by preventing unrelated re-renders.

packages/react-query/src/useIsFetching.ts (2)

2-2: New import added for useQueryState hook

The code now imports the new useQueryState hook which is being used to implement the useIsFetching functionality.


9-12: Good refactoring to leverage useQueryState

The implementation has been simplified by leveraging the new useQueryState hook. This is a good approach that:

  1. Reduces code duplication
  2. Creates a consistent pattern for accessing query states
  3. Leverages the reactive and batched subscription mechanism of useQueryState

The functionality remains the same - returning the count of queries with fetchStatus 'fetching'.

packages/react-query/src/useMutationState.ts (2)

67-67: Simplified subscription logic

The subscription callback has been simplified to directly use notifyManager.batchCalls(onStoreChange) without any intermediate computation or scheduling logic. This is a good simplification that aligns with the pattern used in the new useQueryState hook.


70-80: Improved snapshot getter implementation

The snapshot getter function has been refactored to handle the result computation, comparison, and caching logic. This shift of responsibility from the subscription callback to the snapshot getter is a good architectural change that:

  1. Centralizes the state computation logic in one place
  2. Makes more efficient use of React's synchronization model
  3. Provides better separation of concerns between state computation and notification

The deep comparison with replaceEqualDeep ensures that only actual changes trigger re-renders.

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@visz11
Copy link
Collaborator

visz11 commented Apr 23, 2025

@coderabbitai full review

Copy link

coderabbitai bot commented Apr 23, 2025

✅ Actions performed

Full review triggered.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
packages/react-query/src/useQueryState.ts (2)

48-66: Ensure consistent result reference even with edge cases

The implementation of useSyncExternalStore with refs is good, but there's a potential issue with the server-side rendering getter function.

The server-side rendering getter (third parameter) is using result.current directly, which should be fine in most cases. However, if there are differences between server and client environments, you might want to ensure that the same computation logic is used for both:

   return React.useSyncExternalStore(
     React.useCallback(
       (onStoreChange) =>
         queryCache.subscribe(notifyManager.batchCalls(onStoreChange)),
       [queryCache],
     ),
     () => {
       const nextResult = replaceEqualDeep(
         result.current,
         getResult(queryCache, optionsRef.current),
       )
       if (result.current !== nextResult) {
         result.current = nextResult
       }

       return result.current
     },
-    () => result.current,
+    () => {
+      // Use the same computation logic for server rendering
+      if (!result.current) {
+        result.current = getResult(queryCache, optionsRef.current)
+      }
+      return result.current
+    },
   )!

16-19: Consider documenting the generic type parameter

The QueryStateOptions type uses a generic parameter TResult which defaults to QueryState, but there's no JSDoc to explain what this represents.

Consider adding documentation:

+/**
+ * Options for useQueryState hook.
+ * @template TResult The return type of the selection function, defaults to QueryState.
+ */
 type QueryStateOptions<TResult = QueryState> = {
   filters?: QueryFilters
   select?: (query: Query<unknown, DefaultError, unknown, QueryKey>) => TResult
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4a5990e and 05e18d3.

📒 Files selected for processing (6)
  • packages/react-query/src/__tests__/useIsFetching.test.tsx (1 hunks)
  • packages/react-query/src/__tests__/useMutationState.test.tsx (3 hunks)
  • packages/react-query/src/index.ts (1 hunks)
  • packages/react-query/src/useIsFetching.ts (1 hunks)
  • packages/react-query/src/useMutationState.ts (1 hunks)
  • packages/react-query/src/useQueryState.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/react-query/src/useIsFetching.ts (2)
packages/react-query/src/index.ts (2)
  • useIsFetching (41-41)
  • useQueryState (43-43)
packages/react-query/src/useQueryState.ts (1)
  • useQueryState (33-67)
🪛 GitHub Actions: pr
packages/react-query/src/useQueryState.ts

[error] 39-39: TypeScript error TS2554: Expected 1 arguments, but got 0.

🔇 Additional comments (8)
packages/react-query/src/index.ts (1)

43-43: LGTM! Correct export of the new hook.

The new hook is properly exported, making it available in the public API.

packages/react-query/src/__tests__/useIsFetching.test.tsx (1)

207-209: Hook call order changed - intentional refactoring?

The useIsFetching hook call has been moved before the useQuery call. This change is related to the internal refactoring where useIsFetching now uses the new useQueryState hook.

Please verify this change is intentional. If the order of hook calls matters in the new implementation, it would be helpful to add a comment explaining why:

 function Page() {
+  // useIsFetching must be called before useQuery due to internal implementation details
   const isFetching = useIsFetching({}, queryClient)

   useQuery(
packages/react-query/src/__tests__/useMutationState.test.tsx (2)

69-77: Good improvement using React.memo to isolate hook behavior

Using React.memo to prevent re-renders from other hooks is a good practice that helps isolate the behavior of the hook being tested. This makes the test more reliable and focused.


110-120: Consistent pattern applied to the second test case

The same memoization pattern is correctly applied to this test case as well, ensuring consistent behavior across tests.

packages/react-query/src/useIsFetching.ts (2)

2-2: Good import of the new useQueryState hook.

The integration of the new useQueryState hook aligns with the PR objective of refactoring existing hooks to use the new centralized query state management.


9-12:

❓ Verification inconclusive

Clean implementation using the new hook.

The implementation is concise and follows good composition principles by delegating the subscription logic to useQueryState. The filters are properly extended with fetchStatus: 'fetching' to maintain the original behavior.

Since there are reported test failures in the PR comments specifically related to useIsFetching, verify that the timing of updates is consistent with the previous implementation:


🏁 Script executed:

#!/bin/bash
# Find the failing tests related to useIsFetching
rg -A 5 "useIsFetching.*test" packages/

Length of output: 41


Please verify update timing for useIsFetching

I couldn’t locate any existing tests that cover useIsFetching, so it’s unclear whether the new implementation still triggers updates at the same moment as before. Please manually confirm:

  • The .length returned by useQueryState({ filters: { …filters, fetchStatus: 'fetching' } }, queryClient) updates synchronously with changes in fetchStatus.
  • Consumer components see the same re‑render timing as the previous useIsFetching hook.
packages/react-query/src/useMutationState.ts (2)

67-67: Simplified subscription callback.

Good refactoring to simplify the subscription logic by focusing solely on batching notification calls without additional state management logic.


70-80: Improved state update logic in snapshot getter.

Well-structured refactoring that moves the result computation and comparison logic from the subscription callback to the snapshot getter function. This follows React's recommended patterns for using useSyncExternalStore and creates a more maintainable separation of concerns.

The implementation correctly:

  1. Computes the next result using getResult
  2. Performs deep equality comparison with replaceEqualDeep
  3. Updates the cached result only when necessary
  4. Returns the current result

This approach should improve consistency across query-related hooks in the library.

): Array<TResult> {
const queryCache = useQueryClient(queryClient).getQueryCache()
const optionsRef = React.useRef(options)
const result = React.useRef<Array<TResult>>()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix TypeScript error: Initial value missing for useRef

The TypeScript error indicates that React.useRef expects an initial value, but none is provided here. This is causing the build failure.

Apply this fix:

-  const result = React.useRef<Array<TResult>>()
+  const result = React.useRef<Array<TResult>>([])
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const result = React.useRef<Array<TResult>>()
const result = React.useRef<Array<TResult>>([])
🧰 Tools
🪛 GitHub Actions: pr

[error] 39-39: TypeScript error TS2554: Expected 1 arguments, but got 0.

Comment on lines +33 to +36
export function useQueryState<TResult = QueryState>(
options: QueryStateOptions<TResult> = {},
queryClient?: QueryClient,
): Array<TResult> {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add JSDoc documentation for useQueryState

This is a new public API, and it should have descriptive documentation to help users understand its purpose and usage.

Add JSDoc documentation:

+/**
+ * Hook that provides access to the state of queries in the cache.
+ *
+ * @template TResult The return type of the selection function, defaults to QueryState.
+ * @param options Configuration object to filter and transform query results
+ * @param queryClient Optional QueryClient instance, will use the default from context if not provided
+ * @returns An array of query states or selected results
+ *
+ * @example
+ * // Get all fetching queries
+ * const fetchingQueries = useQueryState({
+ *   filters: { fetchStatus: 'fetching' }
+ * })
+ *
+ * @example
+ * // Get only the data from specific queries
+ * const queryData = useQueryState({
+ *   filters: { queryKey: ['todos'] },
+ *   select: (query) => query.state.data
+ * })
+ */
 export function useQueryState<TResult = QueryState>(
   options: QueryStateOptions<TResult> = {},
   queryClient?: QueryClient,
 ): Array<TResult> {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function useQueryState<TResult = QueryState>(
options: QueryStateOptions<TResult> = {},
queryClient?: QueryClient,
): Array<TResult> {
/**
* Hook that provides access to the state of queries in the cache.
*
* @template TResult The return type of the selection function, defaults to QueryState.
* @param options Configuration object to filter and transform query results
* @param queryClient Optional QueryClient instance, will use the default from context if not provided
* @returns An array of query states or selected results
*
* @example
* // Get all fetching queries
* const fetchingQueries = useQueryState({
* filters: { fetchStatus: 'fetching' }
* })
*
* @example
* // Get only the data from specific queries
* const queryData = useQueryState({
* filters: { queryKey: ['todos'] },
* select: (query) => query.state.data
* })
*/
export function useQueryState<TResult = QueryState>(
options: QueryStateOptions<TResult> = {},
queryClient?: QueryClient,
): Array<TResult> {

Comment on lines +40 to +42
if (!result.current) {
result.current = getResult(queryCache, options)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Revisit initialization logic

Since you're initializing the result.current conditionally, this creates a potential race condition where the initial state might be undefined if accessed during the first render cycle before this check runs.

Consider either:

  1. Setting the initial value directly in the useRef call (like the fix above), or
  2. Add a null check when returning the result to handle potential undefined value
-  if (!result.current) {
-    result.current = getResult(queryCache, options)
-  }
+  // Initialize with current results when ref is empty
+  result.current = result.current || getResult(queryCache, options)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!result.current) {
result.current = getResult(queryCache, options)
}
// Initialize with current results when ref is empty
result.current = result.current || getResult(queryCache, options)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants