Implement support for query client configuration (#612)

* Implement support for query client configuration

* Make sure query client is always initialized

* Fix formatting

* Fix formatting

* Add missing await in index.js

* Separate query client setup into two functions

* Introduce default query client config

* Fix missing export in docs

* Fix missing field warnings

* Add query client setup docs

* Update e2e tests for query client config
This commit is contained in:
Filip Sodić 2022-06-09 10:37:19 +02:00 committed by GitHub
parent b19e95ea51
commit 0b78f658be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 277 additions and 109 deletions

View File

@ -2,9 +2,9 @@
import { callOperation } from '../operations'
import * as resources from '../operations/resources'
const {= actionFnName =} = async (args) => {
async function {= actionFnName =}(args) {
const actionResult = await callOperation('{= actionRoute =}', args)
resources.invalidateQueriesUsing(entitiesUsed)
await resources.invalidateQueriesUsing(entitiesUsed)
return actionResult
}

View File

@ -18,7 +18,7 @@ export default async function login(email, password) {
// TODO(filip): We are currently removing all the queries, but we should
// remove only non-public, user-dependent queries - public queries are
// expected not to change in respect to the currently logged in user.
removeQueries()
await removeQueries()
} catch (error) {
handleApiError(error)
}

View File

@ -1,9 +1,9 @@
import { clearLocalStorage } from '../api.js'
import { invalidateAndRemoveQueries } from '../operations/resources'
export default function logout() {
export default async function logout() {
clearLocalStorage()
// TODO(filip): We are currently invalidating and removing all the queries, but
// we should remove only the non-public, user-dependent ones.
invalidateAndRemoveQueries()
await invalidateAndRemoveQueries()
}

View File

@ -4,7 +4,10 @@ import ReactDOM from 'react-dom'
import { QueryClientProvider } from 'react-query'
import router from './router'
import { queryClient } from './queryClient'
import {
initializeQueryClient,
queryClientInitialized,
} from './queryClient'
import * as serviceWorker from './serviceWorker'
{=# doesClientSetupFnExist =}
@ -19,8 +22,9 @@ async function startApp() {
{=# doesClientSetupFnExist =}
await {= clientSetupJsFnIdentifier =}()
{=/ doesClientSetupFnExist =}
initializeQueryClient()
render()
await render()
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
@ -28,7 +32,8 @@ async function startApp() {
serviceWorker.unregister()
}
function render() {
async function render() {
const queryClient = await queryClientInitialized
ReactDOM.render(
<QueryClientProvider client={queryClient}>
{ router }

View File

@ -1,5 +1,5 @@
{{= {= =} =}}
import { queryClient } from '../queryClient'
import { queryClientInitialized } from '../queryClient'
// Map where key is resource name and value is Set
@ -31,26 +31,26 @@ export function addResourcesUsedByQuery(queryCacheKey, resources) {
export function getQueriesUsingResource(resource) {
return Array.from(resourceToQueryCacheKeys.get(resource) || [])
}
/**
* Invalidates all queries that are using specified resources.
* @param {string[]} resources - Names of resources.
*/
export function invalidateQueriesUsing(resources) {
const queryCacheKeysToInvalidate = new Set()
for (const resource of resources) {
getQueriesUsingResource(resource).forEach(key => queryCacheKeysToInvalidate.add(key))
}
for (const queryCacheKey of queryCacheKeysToInvalidate) {
export async function invalidateQueriesUsing(resources) {
const queryClient = await queryClientInitialized
const queryCacheKeysToInvalidate = new Set(resources.flatMap(getQueriesUsingResource))
queryCacheKeysToInvalidate.forEach(queryCacheKey =>
queryClient.invalidateQueries(queryCacheKey)
}
)
}
export function removeQueries() {
export async function removeQueries() {
const queryClient = await queryClientInitialized
queryClient.removeQueries()
}
export function invalidateAndRemoveQueries() {
export async function invalidateAndRemoveQueries() {
const queryClient = await queryClientInitialized
// If we don't invalidate the queries before removing them, Wasp will stay on
// the same page. The user would have to manually refresh the page to "finish"
// logging out.

View File

@ -1,6 +1,7 @@
import { useQuery as rqUseQuery } from 'react-query'
export { configureQueryClient } from '../queryClient'
export function useQuery(queryFn, queryFnArgs, config) {
export function useQuery(queryFn, queryFnArgs, options) {
if (typeof queryFn !== 'function') {
throw new TypeError('useQuery requires queryFn to be a function.')
}
@ -11,6 +12,6 @@ export function useQuery(queryFn, queryFnArgs, config) {
return rqUseQuery({
queryKey: [queryFn.queryCacheKey, queryFnArgs],
queryFn: () => queryFn(queryFnArgs),
...config
...options
})
}

View File

@ -1,3 +1,23 @@
import { QueryClient } from 'react-query'
export const queryClient = new QueryClient()
const defaultQueryClientConfig = {}
let queryClientConfig, resolveQueryClientInitialized, isQueryClientInitialized
export const queryClientInitialized = new Promise(resolve => {
resolveQueryClientInitialized = resolve
});
export function configureQueryClient(config) {
if (isQueryClientInitialized) {
throw new Error("Attempted to configure the QueryClient after initialization")
}
queryClientConfig = config
}
export function initializeQueryClient() {
const queryClient = new QueryClient(queryClientConfig ?? defaultQueryClientConfig)
isQueryClientInitialized = true;
resolveQueryClientInitialized(queryClient)
}

View File

@ -291,7 +291,7 @@
"file",
"web-app/src/index.js"
],
"a477184a6e6e7cb33e056febc8a4a1e1132ecc697763855fa2af07cf02c79908"
"d0aeef2633b26de4c5d7064acc7c4533212cee8d3b36e91a3a785930621d02e4"
],
[
[
@ -312,21 +312,21 @@
"file",
"web-app/src/operations/resources.js"
],
"4772a216b647ace3eedace9b02897922725b58131031d21be59187b1652ccade"
"9bccf509e1a3e04e24444eacd69e0f093e590a9b85325bedb6f1d52ac85ead3c"
],
[
[
"file",
"web-app/src/queries/index.js"
],
"39a659c6ed82cbbc38b834b607e049646e0d70e104d01317830f225629a5f14c"
"8510924f80b32cc0f67ca39fad9d97c4ce5d9695015da3ec8457e91a88868c78"
],
[
[
"file",
"web-app/src/queryClient.js"
],
"f53c6e82b0e1b13dd2c2fff423460c88cd1c331e154867edeb7cd5f98c3586e4"
"3adf1c16b436ce5eb71f0ef7a4ec2bcd04e0dafbc2b43291c5050d1621cb764c"
],
[
[

View File

@ -3,7 +3,10 @@ import ReactDOM from 'react-dom'
import { QueryClientProvider } from 'react-query'
import router from './router'
import { queryClient } from './queryClient'
import {
initializeQueryClient,
queryClientInitialized,
} from './queryClient'
import * as serviceWorker from './serviceWorker'
@ -12,8 +15,9 @@ import './index.css'
startApp()
async function startApp() {
initializeQueryClient()
render()
await render()
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
@ -21,7 +25,8 @@ async function startApp() {
serviceWorker.unregister()
}
function render() {
async function render() {
const queryClient = await queryClientInitialized
ReactDOM.render(
<QueryClientProvider client={queryClient}>
{ router }

View File

@ -1,4 +1,4 @@
import { queryClient } from '../queryClient'
import { queryClientInitialized } from '../queryClient'
// Map where key is resource name and value is Set
@ -30,26 +30,26 @@ export function addResourcesUsedByQuery(queryCacheKey, resources) {
export function getQueriesUsingResource(resource) {
return Array.from(resourceToQueryCacheKeys.get(resource) || [])
}
/**
* Invalidates all queries that are using specified resources.
* @param {string[]} resources - Names of resources.
*/
export function invalidateQueriesUsing(resources) {
const queryCacheKeysToInvalidate = new Set()
for (const resource of resources) {
getQueriesUsingResource(resource).forEach(key => queryCacheKeysToInvalidate.add(key))
}
for (const queryCacheKey of queryCacheKeysToInvalidate) {
export async function invalidateQueriesUsing(resources) {
const queryClient = await queryClientInitialized
const queryCacheKeysToInvalidate = new Set(resources.flatMap(getQueriesUsingResource))
queryCacheKeysToInvalidate.forEach(queryCacheKey =>
queryClient.invalidateQueries(queryCacheKey)
}
)
}
export function removeQueries() {
export async function removeQueries() {
const queryClient = await queryClientInitialized
queryClient.removeQueries()
}
export function invalidateAndRemoveQueries() {
export async function invalidateAndRemoveQueries() {
const queryClient = await queryClientInitialized
// If we don't invalidate the queries before removing them, Wasp will stay on
// the same page. The user would have to manually refresh the page to "finish"
// logging out.

View File

@ -1,6 +1,7 @@
import { useQuery as rqUseQuery } from 'react-query'
export { configureQueryClient } from '../queryClient'
export function useQuery(queryFn, queryFnArgs, config) {
export function useQuery(queryFn, queryFnArgs, options) {
if (typeof queryFn !== 'function') {
throw new TypeError('useQuery requires queryFn to be a function.')
}
@ -11,6 +12,6 @@ export function useQuery(queryFn, queryFnArgs, config) {
return rqUseQuery({
queryKey: [queryFn.queryCacheKey, queryFnArgs],
queryFn: () => queryFn(queryFnArgs),
...config
...options
})
}

View File

@ -1,3 +1,23 @@
import { QueryClient } from 'react-query'
export const queryClient = new QueryClient()
const defaultQueryClientConfig = {}
let queryClientConfig, resolveQueryClientInitialized, isQueryClientInitialized
export const queryClientInitialized = new Promise(resolve => {
resolveQueryClientInitialized = resolve
});
export function configureQueryClient(config) {
if (isQueryClientInitialized) {
throw new Error("Attempted to configure the QueryClient after initialization")
}
queryClientConfig = config
}
export function initializeQueryClient() {
const queryClient = new QueryClient(queryClientConfig ?? defaultQueryClientConfig)
isQueryClientInitialized = true;
resolveQueryClientInitialized(queryClient)
}

View File

@ -291,7 +291,7 @@
"file",
"web-app/src/index.js"
],
"a477184a6e6e7cb33e056febc8a4a1e1132ecc697763855fa2af07cf02c79908"
"d0aeef2633b26de4c5d7064acc7c4533212cee8d3b36e91a3a785930621d02e4"
],
[
[
@ -312,21 +312,21 @@
"file",
"web-app/src/operations/resources.js"
],
"4772a216b647ace3eedace9b02897922725b58131031d21be59187b1652ccade"
"9bccf509e1a3e04e24444eacd69e0f093e590a9b85325bedb6f1d52ac85ead3c"
],
[
[
"file",
"web-app/src/queries/index.js"
],
"39a659c6ed82cbbc38b834b607e049646e0d70e104d01317830f225629a5f14c"
"8510924f80b32cc0f67ca39fad9d97c4ce5d9695015da3ec8457e91a88868c78"
],
[
[
"file",
"web-app/src/queryClient.js"
],
"f53c6e82b0e1b13dd2c2fff423460c88cd1c331e154867edeb7cd5f98c3586e4"
"3adf1c16b436ce5eb71f0ef7a4ec2bcd04e0dafbc2b43291c5050d1621cb764c"
],
[
[

View File

@ -3,7 +3,10 @@ import ReactDOM from 'react-dom'
import { QueryClientProvider } from 'react-query'
import router from './router'
import { queryClient } from './queryClient'
import {
initializeQueryClient,
queryClientInitialized,
} from './queryClient'
import * as serviceWorker from './serviceWorker'
@ -12,8 +15,9 @@ import './index.css'
startApp()
async function startApp() {
initializeQueryClient()
render()
await render()
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
@ -21,7 +25,8 @@ async function startApp() {
serviceWorker.unregister()
}
function render() {
async function render() {
const queryClient = await queryClientInitialized
ReactDOM.render(
<QueryClientProvider client={queryClient}>
{ router }

View File

@ -1,4 +1,4 @@
import { queryClient } from '../queryClient'
import { queryClientInitialized } from '../queryClient'
// Map where key is resource name and value is Set
@ -30,26 +30,26 @@ export function addResourcesUsedByQuery(queryCacheKey, resources) {
export function getQueriesUsingResource(resource) {
return Array.from(resourceToQueryCacheKeys.get(resource) || [])
}
/**
* Invalidates all queries that are using specified resources.
* @param {string[]} resources - Names of resources.
*/
export function invalidateQueriesUsing(resources) {
const queryCacheKeysToInvalidate = new Set()
for (const resource of resources) {
getQueriesUsingResource(resource).forEach(key => queryCacheKeysToInvalidate.add(key))
}
for (const queryCacheKey of queryCacheKeysToInvalidate) {
export async function invalidateQueriesUsing(resources) {
const queryClient = await queryClientInitialized
const queryCacheKeysToInvalidate = new Set(resources.flatMap(getQueriesUsingResource))
queryCacheKeysToInvalidate.forEach(queryCacheKey =>
queryClient.invalidateQueries(queryCacheKey)
}
)
}
export function removeQueries() {
export async function removeQueries() {
const queryClient = await queryClientInitialized
queryClient.removeQueries()
}
export function invalidateAndRemoveQueries() {
export async function invalidateAndRemoveQueries() {
const queryClient = await queryClientInitialized
// If we don't invalidate the queries before removing them, Wasp will stay on
// the same page. The user would have to manually refresh the page to "finish"
// logging out.

View File

@ -1,6 +1,7 @@
import { useQuery as rqUseQuery } from 'react-query'
export { configureQueryClient } from '../queryClient'
export function useQuery(queryFn, queryFnArgs, config) {
export function useQuery(queryFn, queryFnArgs, options) {
if (typeof queryFn !== 'function') {
throw new TypeError('useQuery requires queryFn to be a function.')
}
@ -11,6 +12,6 @@ export function useQuery(queryFn, queryFnArgs, config) {
return rqUseQuery({
queryKey: [queryFn.queryCacheKey, queryFnArgs],
queryFn: () => queryFn(queryFnArgs),
...config
...options
})
}

View File

@ -1,3 +1,23 @@
import { QueryClient } from 'react-query'
export const queryClient = new QueryClient()
const defaultQueryClientConfig = {}
let queryClientConfig, resolveQueryClientInitialized, isQueryClientInitialized
export const queryClientInitialized = new Promise(resolve => {
resolveQueryClientInitialized = resolve
});
export function configureQueryClient(config) {
if (isQueryClientInitialized) {
throw new Error("Attempted to configure the QueryClient after initialization")
}
queryClientConfig = config
}
export function initializeQueryClient() {
const queryClient = new QueryClient(queryClientConfig ?? defaultQueryClientConfig)
isQueryClientInitialized = true;
resolveQueryClientInitialized(queryClient)
}

View File

@ -312,7 +312,7 @@
"file",
"web-app/src/index.js"
],
"a477184a6e6e7cb33e056febc8a4a1e1132ecc697763855fa2af07cf02c79908"
"d0aeef2633b26de4c5d7064acc7c4533212cee8d3b36e91a3a785930621d02e4"
],
[
[
@ -333,21 +333,21 @@
"file",
"web-app/src/operations/resources.js"
],
"4772a216b647ace3eedace9b02897922725b58131031d21be59187b1652ccade"
"9bccf509e1a3e04e24444eacd69e0f093e590a9b85325bedb6f1d52ac85ead3c"
],
[
[
"file",
"web-app/src/queries/index.js"
],
"39a659c6ed82cbbc38b834b607e049646e0d70e104d01317830f225629a5f14c"
"8510924f80b32cc0f67ca39fad9d97c4ce5d9695015da3ec8457e91a88868c78"
],
[
[
"file",
"web-app/src/queryClient.js"
],
"f53c6e82b0e1b13dd2c2fff423460c88cd1c331e154867edeb7cd5f98c3586e4"
"3adf1c16b436ce5eb71f0ef7a4ec2bcd04e0dafbc2b43291c5050d1621cb764c"
],
[
[

View File

@ -3,7 +3,10 @@ import ReactDOM from 'react-dom'
import { QueryClientProvider } from 'react-query'
import router from './router'
import { queryClient } from './queryClient'
import {
initializeQueryClient,
queryClientInitialized,
} from './queryClient'
import * as serviceWorker from './serviceWorker'
@ -12,8 +15,9 @@ import './index.css'
startApp()
async function startApp() {
initializeQueryClient()
render()
await render()
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
@ -21,7 +25,8 @@ async function startApp() {
serviceWorker.unregister()
}
function render() {
async function render() {
const queryClient = await queryClientInitialized
ReactDOM.render(
<QueryClientProvider client={queryClient}>
{ router }

View File

@ -1,4 +1,4 @@
import { queryClient } from '../queryClient'
import { queryClientInitialized } from '../queryClient'
// Map where key is resource name and value is Set
@ -30,26 +30,26 @@ export function addResourcesUsedByQuery(queryCacheKey, resources) {
export function getQueriesUsingResource(resource) {
return Array.from(resourceToQueryCacheKeys.get(resource) || [])
}
/**
* Invalidates all queries that are using specified resources.
* @param {string[]} resources - Names of resources.
*/
export function invalidateQueriesUsing(resources) {
const queryCacheKeysToInvalidate = new Set()
for (const resource of resources) {
getQueriesUsingResource(resource).forEach(key => queryCacheKeysToInvalidate.add(key))
}
for (const queryCacheKey of queryCacheKeysToInvalidate) {
export async function invalidateQueriesUsing(resources) {
const queryClient = await queryClientInitialized
const queryCacheKeysToInvalidate = new Set(resources.flatMap(getQueriesUsingResource))
queryCacheKeysToInvalidate.forEach(queryCacheKey =>
queryClient.invalidateQueries(queryCacheKey)
}
)
}
export function removeQueries() {
export async function removeQueries() {
const queryClient = await queryClientInitialized
queryClient.removeQueries()
}
export function invalidateAndRemoveQueries() {
export async function invalidateAndRemoveQueries() {
const queryClient = await queryClientInitialized
// If we don't invalidate the queries before removing them, Wasp will stay on
// the same page. The user would have to manually refresh the page to "finish"
// logging out.

View File

@ -1,6 +1,7 @@
import { useQuery as rqUseQuery } from 'react-query'
export { configureQueryClient } from '../queryClient'
export function useQuery(queryFn, queryFnArgs, config) {
export function useQuery(queryFn, queryFnArgs, options) {
if (typeof queryFn !== 'function') {
throw new TypeError('useQuery requires queryFn to be a function.')
}
@ -11,6 +12,6 @@ export function useQuery(queryFn, queryFnArgs, config) {
return rqUseQuery({
queryKey: [queryFn.queryCacheKey, queryFnArgs],
queryFn: () => queryFn(queryFnArgs),
...config
...options
})
}

View File

@ -1,3 +1,23 @@
import { QueryClient } from 'react-query'
export const queryClient = new QueryClient()
const defaultQueryClientConfig = {}
let queryClientConfig, resolveQueryClientInitialized, isQueryClientInitialized
export const queryClientInitialized = new Promise(resolve => {
resolveQueryClientInitialized = resolve
});
export function configureQueryClient(config) {
if (isQueryClientInitialized) {
throw new Error("Attempted to configure the QueryClient after initialization")
}
queryClientConfig = config
}
export function initializeQueryClient() {
const queryClient = new QueryClient(queryClientConfig ?? defaultQueryClientConfig)
isQueryClientInitialized = true;
resolveQueryClientInitialized(queryClient)
}

View File

@ -291,7 +291,7 @@
"file",
"web-app/src/index.js"
],
"a477184a6e6e7cb33e056febc8a4a1e1132ecc697763855fa2af07cf02c79908"
"d0aeef2633b26de4c5d7064acc7c4533212cee8d3b36e91a3a785930621d02e4"
],
[
[
@ -312,21 +312,21 @@
"file",
"web-app/src/operations/resources.js"
],
"4772a216b647ace3eedace9b02897922725b58131031d21be59187b1652ccade"
"9bccf509e1a3e04e24444eacd69e0f093e590a9b85325bedb6f1d52ac85ead3c"
],
[
[
"file",
"web-app/src/queries/index.js"
],
"39a659c6ed82cbbc38b834b607e049646e0d70e104d01317830f225629a5f14c"
"8510924f80b32cc0f67ca39fad9d97c4ce5d9695015da3ec8457e91a88868c78"
],
[
[
"file",
"web-app/src/queryClient.js"
],
"f53c6e82b0e1b13dd2c2fff423460c88cd1c331e154867edeb7cd5f98c3586e4"
"3adf1c16b436ce5eb71f0ef7a4ec2bcd04e0dafbc2b43291c5050d1621cb764c"
],
[
[

View File

@ -3,7 +3,10 @@ import ReactDOM from 'react-dom'
import { QueryClientProvider } from 'react-query'
import router from './router'
import { queryClient } from './queryClient'
import {
initializeQueryClient,
queryClientInitialized,
} from './queryClient'
import * as serviceWorker from './serviceWorker'
@ -12,8 +15,9 @@ import './index.css'
startApp()
async function startApp() {
initializeQueryClient()
render()
await render()
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
@ -21,7 +25,8 @@ async function startApp() {
serviceWorker.unregister()
}
function render() {
async function render() {
const queryClient = await queryClientInitialized
ReactDOM.render(
<QueryClientProvider client={queryClient}>
{ router }

View File

@ -1,4 +1,4 @@
import { queryClient } from '../queryClient'
import { queryClientInitialized } from '../queryClient'
// Map where key is resource name and value is Set
@ -30,26 +30,26 @@ export function addResourcesUsedByQuery(queryCacheKey, resources) {
export function getQueriesUsingResource(resource) {
return Array.from(resourceToQueryCacheKeys.get(resource) || [])
}
/**
* Invalidates all queries that are using specified resources.
* @param {string[]} resources - Names of resources.
*/
export function invalidateQueriesUsing(resources) {
const queryCacheKeysToInvalidate = new Set()
for (const resource of resources) {
getQueriesUsingResource(resource).forEach(key => queryCacheKeysToInvalidate.add(key))
}
for (const queryCacheKey of queryCacheKeysToInvalidate) {
export async function invalidateQueriesUsing(resources) {
const queryClient = await queryClientInitialized
const queryCacheKeysToInvalidate = new Set(resources.flatMap(getQueriesUsingResource))
queryCacheKeysToInvalidate.forEach(queryCacheKey =>
queryClient.invalidateQueries(queryCacheKey)
}
)
}
export function removeQueries() {
export async function removeQueries() {
const queryClient = await queryClientInitialized
queryClient.removeQueries()
}
export function invalidateAndRemoveQueries() {
export async function invalidateAndRemoveQueries() {
const queryClient = await queryClientInitialized
// If we don't invalidate the queries before removing them, Wasp will stay on
// the same page. The user would have to manually refresh the page to "finish"
// logging out.

View File

@ -1,6 +1,7 @@
import { useQuery as rqUseQuery } from 'react-query'
export { configureQueryClient } from '../queryClient'
export function useQuery(queryFn, queryFnArgs, config) {
export function useQuery(queryFn, queryFnArgs, options) {
if (typeof queryFn !== 'function') {
throw new TypeError('useQuery requires queryFn to be a function.')
}
@ -11,6 +12,6 @@ export function useQuery(queryFn, queryFnArgs, config) {
return rqUseQuery({
queryKey: [queryFn.queryCacheKey, queryFnArgs],
queryFn: () => queryFn(queryFnArgs),
...config
...options
})
}

View File

@ -1,3 +1,23 @@
import { QueryClient } from 'react-query'
export const queryClient = new QueryClient()
const defaultQueryClientConfig = {}
let queryClientConfig, resolveQueryClientInitialized, isQueryClientInitialized
export const queryClientInitialized = new Promise(resolve => {
resolveQueryClientInitialized = resolve
});
export function configureQueryClient(config) {
if (isQueryClientInitialized) {
throw new Error("Attempted to configure the QueryClient after initialization")
}
queryClientConfig = config
}
export function initializeQueryClient() {
const queryClient = new QueryClient(queryClientConfig ?? defaultQueryClientConfig)
isQueryClientInitialized = true;
resolveQueryClientInitialized(queryClient)
}

View File

@ -132,6 +132,7 @@ spec_AppSpecValid = do
{ AS.App.title = "Test App",
AS.App.db = Nothing,
AS.App.server = Nothing,
AS.App.client = Nothing,
AS.App.auth = Nothing,
AS.App.dependencies = Nothing,
AS.App.head = Nothing

View File

@ -30,6 +30,7 @@ spec_WebAppGenerator = do
{ AS.App.title = "Test App",
AS.App.db = Nothing,
AS.App.server = Nothing,
AS.App.client = Nothing,
AS.App.auth = Nothing,
AS.App.dependencies = Nothing,
AS.App.head = Nothing

View File

@ -284,8 +284,12 @@ This hook comes bundled with Wasp and is a thin wrapper around the `useQuery` ho
Wasp's `useQuery` hook accepts three arguments:
- `queryFn` (required): A Wasp query declared in the previous step or, in other words, the client-side query function generated by Wasp based on a `query` declaration.
- `queryFnArgs` (optional): The arguments object (payload) you wish to pass into the query. The query's NodeJS implementation will receive this object as its first positional argument.
- `config` (optional): A _react-query_ `config` object.
- `queryFnArgs` (optional): The arguments object (payload) you wish to pass into the Query. The Query's NodeJS implementation will receive this object as its first positional argument.
- `options` (optional): A _react-query_ `options` object. Use this to change
[the default
behaviour](https://react-query.tanstack.com/guides/important-defaults) for
this particular query. If you want to change the global defaults, you can do
so in the [client setup function](#overriding-default-behaviour-for-queries).
Wasp's `useQuery` hook behaves mostly the same as [_react-query_'s `useQuery` hook](https://react-query.tanstack.com/docs/api#usequery), the only difference being in not having to supply the key (Wasp does this automatically under the hood).
@ -961,7 +965,7 @@ client-side periodic jobs).
Here's a dummy example of such a function:
```js title="ext/myClientSetupCode.js"
async function mySetupFunction() {
export default async function mySetupFunction() {
let count = 1;
setInterval(
() => console.log(`You have been online for ${count++} hours.`),
@ -970,6 +974,38 @@ async function mySetupFunction() {
}
```
##### Overriding default behaviour for Queries
As mentioned, our `useQuery` hook uses _react-query_'s hook of the same name.
Since _react-query_ comes configured with aggressive but sane default options,
you most likely won't have to change those defaults for all Queries (you can
change them for a single Query using the `options` object, as described
[here](#the-usequery-hook)).
Still, if you do need the global defaults, you can do so inside client setup
function. Wasp exposes a `configureQueryClient` hook that lets you configure
_react-query_'s `QueryClient` object:
```js title="ext/myClientSetupCode.js"
import { configureQueryClient } from '@wasp/queries'
export default async function mySetupFunction() {
// ... some setup
configureQueryClient({
defaultOptions: {
queries: {
staleTime: Infinity,
}
}
})
// ... some more setup
}
```
Make sure to pass in an object expected by the `QueryClient`'s construcor, as
explained in
[_react-query_'s docs](https://react-query.tanstack.com/reference/QueryClient).
## Server configuration
Via `server` field of `app` declaration, you can configure behaviour of the Node.js server (one that is executing wasp operations).