snapshot of https://github.com/TanStack/query.git (main, 2026-09-16; blobs > 131072B omitted)
Some checks failed
autofix.ci / autofix (push) Failing after 4s
Release / Release (push) Has been skipped
GitHub Actions Security Analysis / Run zizmor (push) Failing after 2s

This commit is contained in:
upstream-mirror
2026-09-16 01:13:08 +05:00
commit 3a013ccdfe
3570 changed files with 490194 additions and 0 deletions

27
examples/react/algolia/.gitignore vendored Normal file
View File

@@ -0,0 +1,27 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
pnpm-lock.yaml
yarn.lock
package-lock.json
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

View File

@@ -0,0 +1,6 @@
# Example
To run this example:
- `npm install`
- `npm run dev`

View File

@@ -0,0 +1,9 @@
import { tanstackConfig } from '@tanstack/eslint-config'
import pluginQuery from '@tanstack/eslint-plugin-query'
import pluginReact from '@eslint-react/eslint-plugin'
export default [
...tanstackConfig,
...pluginQuery.configs['flat/recommended'],
pluginReact.configs.recommended,
]

View File

@@ -0,0 +1,16 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" type="image/svg+xml" href="/emblem-light.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<title>TanStack Query React Algolia example App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>

View File

@@ -0,0 +1,25 @@
{
"name": "@tanstack/query-example-react-algolia",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@algolia/client-search": "5.2.1",
"@tanstack/react-query": "^5.102.8",
"@tanstack/react-query-devtools": "^5.102.8",
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"@tanstack/eslint-plugin-query": "^5.102.8",
"@types/react": "^18.2.79",
"@types/react-dom": "^18.2.25",
"@vitejs/plugin-react": "^4.3.4",
"typescript": "5.8.3",
"vite": "^6.4.1"
}
}

View File

@@ -0,0 +1,17 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import './styles.css'
import Search from './Search'
const queryClient = new QueryClient()
export default function App() {
return (
<QueryClientProvider client={queryClient}>
<div className="App">
<h1>TanStack Query with Algolia</h1>
<Search />
</div>
</QueryClientProvider>
)
}

View File

@@ -0,0 +1,24 @@
import * as React from 'react'
import SearchResults from './SearchResults'
export default function Search() {
const [query, setQuery] = React.useState('')
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>) => {
event.preventDefault()
// It is recommended to debounce this event in prod
setQuery(event.target.value)
}
return (
<div>
<input
onChange={handleOnChange}
value={query}
placeholder="Search products"
/>
<SearchResults query={query} />
</div>
)
}

View File

@@ -0,0 +1,72 @@
import useAlgolia from './useAlgolia'
type Product = {
name: string
shortDescription: string
salePrice: number
}
type SearchResultsProps = {
query: string
}
export default function SearchResults({ query = '' }: SearchResultsProps) {
const {
hits,
isLoading,
isFetching,
status,
hasNextPage,
isFetchingNextPage,
fetchNextPage,
} = useAlgolia<Product>({
indexName: 'bestbuy',
query,
hitsPerPage: 5,
staleTime: 1000 * 30, // 30s
gcTime: 1000 * 60 * 15, // 15m
})
if (!query) return null
if (isLoading) return <div className="loading">Loading...</div>
return (
<div>
<div className="search-status">
Status: {status} {isFetching && <span>fetching...</span>}
</div>
<div>
<div className="search-result">
{hits && hits.length > 0 ? (
hits.map((product) => (
<li key={product.objectID} className="product">
<span className="product-name">{product.name}</span>
{product.shortDescription && (
<>
<br />
<span className="product-description">
{product.shortDescription}
</span>
</>
)}
<br />
<span className="product-price">${product.salePrice}</span>
</li>
))
) : (
<h3>No products found!</h3>
)}
</div>
{hasNextPage && (
<div className="search-more" onClick={() => fetchNextPage()}>
more
</div>
)}
{isFetchingNextPage && (
<div className="search-status">Fetching next page...</div>
)}
</div>
</div>
)
}

View File

@@ -0,0 +1,37 @@
import { searchClient } from '@algolia/client-search'
import type { Hit } from '@algolia/client-search'
// From Algolia example
// https://github.com/algolia/react-instantsearch
const ALGOLIA_APP_ID = 'latency'
const ALGOLIA_SEARCH_API_KEY = '6be0576ff61c053d5f9a3225e2a90f76'
type SearchOptions = {
indexName: string
query: string
pageParam: number
hitsPerPage: number
}
export async function search<TData>({
indexName,
query,
pageParam,
hitsPerPage = 10,
}: SearchOptions): Promise<{
hits: Array<Hit<TData>>
nextPage: number | undefined
}> {
const client = searchClient(ALGOLIA_APP_ID, ALGOLIA_SEARCH_API_KEY)
console.log('algolia:search', { indexName, query, pageParam, hitsPerPage })
const { hits, page, nbPages } = await client.searchSingleIndex<TData>({
indexName,
searchParams: { query, page: pageParam, hitsPerPage },
})
const nextPage = page + 1 < nbPages ? page + 1 : undefined
return { hits, nextPage }
}

View File

@@ -0,0 +1,7 @@
import ReactDOM from 'react-dom/client'
import App from './App'
const rootElement = document.getElementById('root')
if (!rootElement) throw new Error('Missing #root element')
ReactDOM.createRoot(rootElement).render(<App />)

View File

@@ -0,0 +1,49 @@
.App {
font-family: sans-serif;
font-size: 14px;
padding: 20px;
}
.loading {
padding-top: 20px;
padding-left: 20px;
color: darkmagenta;
}
.search-status {
padding-top: 20px;
padding-left: 20px;
color: gray;
}
.search-result {
padding-left: 20px;
padding-top: 20px;
}
.search-more {
color: blue;
padding-left: 20px;
padding-top: 20px;
cursor: pointer;
font-weight: bold;
text-transform: uppercase;
}
.product {
padding-bottom: 5px;
}
.product-name {
font-weight: bold;
font-size: 12px;
}
.product-description {
font-size: 12px;
}
.product-price {
font-size: 12px;
font-weight: bold;
}

View File

@@ -0,0 +1,34 @@
import { skipToken, useInfiniteQuery } from '@tanstack/react-query'
import { search } from './algolia'
export type UseAlgoliaOptions = {
indexName: string
query: string
hitsPerPage?: number
staleTime?: number
gcTime?: number
}
export default function useAlgolia<TData>({
indexName,
query,
hitsPerPage = 10,
staleTime,
gcTime,
}: UseAlgoliaOptions) {
const queryInfo = useInfiniteQuery({
queryKey: ['algolia', indexName, query, hitsPerPage],
queryFn: query
? ({ pageParam }) =>
search<TData>({ indexName, query, pageParam, hitsPerPage })
: skipToken,
initialPageParam: 0,
getNextPageParam: (lastPage) => lastPage.nextPage,
staleTime,
gcTime,
})
const hits = queryInfo.data?.pages.map((page) => page.hits).flat()
return { ...queryInfo, hits }
}

View File

@@ -0,0 +1,24 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "Bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"]
}

View File

@@ -0,0 +1,6 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
})