Skip to content

Commit 1a38d17

Browse files
authored
examples(react): Algolia search example (#4971)
* docs: example: algolia * fix: remove empty line if desc is null * fix: stale time value * refactor: use vite and examples structure * fix: remove deprecated doc files * docs: add algolia example in the config.json
1 parent 21439e6 commit 1a38d17

17 files changed

+570
-39
lines changed

docs/config.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,10 @@
277277
{
278278
"label": "Offline Queries and Mutations",
279279
"to": "react/examples/react/offline"
280+
},
281+
{
282+
"label": "Algolia",
283+
"to": "react/examples/react/algolia"
280284
}
281285
]
282286
},

examples/react/algolia/.eslintrc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"extends": ["react-app", "prettier", "plugin:@tanstack/eslint-plugin-query/recommended"],
3+
"rules": {
4+
"react/jsx-uses-react": "off",
5+
"react/react-in-jsx-scope": "off"
6+
}
7+
}

examples/react/algolia/.gitignore

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
8+
# testing
9+
/coverage
10+
11+
# production
12+
/build
13+
14+
pnpm-lock.yaml
15+
yarn.lock
16+
package-lock.json
17+
18+
# misc
19+
.DS_Store
20+
.env.local
21+
.env.development.local
22+
.env.test.local
23+
.env.production.local
24+
25+
npm-debug.log*
26+
yarn-debug.log*
27+
yarn-error.log*

examples/react/algolia/.prettierrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}

examples/react/algolia/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Example
2+
3+
To run this example:
4+
5+
- `npm install`
6+
- `npm run dev`

examples/react/algolia/index.html

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<link rel="shortcut icon" type="image/svg+xml" href="/emblem-light.svg" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1" />
7+
<meta name="theme-color" content="#000000" />
8+
9+
<title>TanStack Query React Algolia example App</title>
10+
</head>
11+
<body>
12+
<noscript>You need to enable JavaScript to run this app.</noscript>
13+
<div id="root"></div>
14+
<script type="module" src="/src/index.tsx"></script>
15+
</body>
16+
</html>

examples/react/algolia/package.json

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"name": "@tanstack/query-example-react-algolia",
3+
"version": "0.0.1",
4+
"main": "src/index.tsx",
5+
"scripts": {
6+
"dev": "vite",
7+
"build": "tsc && vite build",
8+
"preview": "vite preview"
9+
},
10+
"dependencies": {
11+
"@tanstack/react-query": "^4.7.1",
12+
"@tanstack/react-query-devtools": "^4.7.1",
13+
"@algolia/client-search": "4.11.0",
14+
"@algolia/transporter": "4.11.0",
15+
"algoliasearch": "4.12.2"
16+
},
17+
"devDependencies": {
18+
"@tanstack/eslint-plugin-query": "^4.13.0",
19+
"@vitejs/plugin-react": "^2.0.0",
20+
"vite": "^3.0.0",
21+
"react": "^18.2.0",
22+
"react-dom": "^18.2.0",
23+
"typescript": "^4.7.4",
24+
"@types/react": "^18.0.14",
25+
"@types/react-dom": "^18.0.5"
26+
},
27+
"browserslist": {
28+
"production": [
29+
">0.2%",
30+
"not dead",
31+
"not op_mini all"
32+
],
33+
"development": [
34+
"last 1 chrome version",
35+
"last 1 firefox version",
36+
"last 1 safari version"
37+
]
38+
}
39+
}

examples/react/algolia/src/App.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
2+
3+
import "./styles.css";
4+
import Search from "./Search";
5+
6+
const queryClient = new QueryClient();
7+
8+
export default function App() {
9+
return (
10+
<QueryClientProvider client={queryClient}>
11+
<div className="App">
12+
<h1>TanStack Query with Algolia</h1>
13+
<Search />
14+
</div>
15+
</QueryClientProvider>
16+
);
17+
}

examples/react/algolia/src/Search.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { useState } from "react";
2+
3+
import SearchResults from "./SearchResults";
4+
5+
export default function Search() {
6+
const [query, setQuery] = useState("");
7+
8+
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>) => {
9+
event.preventDefault();
10+
// It is recommended to debounce this event in prod
11+
setQuery(event.target.value);
12+
};
13+
14+
return (
15+
<div>
16+
<input
17+
onChange={handleOnChange}
18+
value={query}
19+
placeholder="Search products"
20+
/>
21+
<SearchResults query={query} />
22+
</div>
23+
);
24+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import useAlgolia from "./useAlgolia";
2+
3+
type Product = {
4+
name: string;
5+
shortDescription: string;
6+
salePrice: number;
7+
};
8+
9+
type SearchResultsProps = {
10+
query: string;
11+
};
12+
13+
export default function SearchResults({ query = "" }: SearchResultsProps) {
14+
const {
15+
hits,
16+
isLoading,
17+
isFetching,
18+
status,
19+
hasNextPage,
20+
isFetchingNextPage,
21+
fetchNextPage,
22+
} = useAlgolia<Product>({
23+
indexName: "bestbuy",
24+
query,
25+
hitsPerPage: 5,
26+
staleTime: 1000 * 30, // 30s
27+
cacheTime: 1000 * 60 * 15, // 15m
28+
enabled: !!query,
29+
});
30+
31+
if (!query) return null;
32+
33+
if (isLoading) return <div className="loading">Loading...</div>;
34+
35+
return (
36+
<div>
37+
<div className="search-status">
38+
Satus: {status} {isFetching && <span>fetching...</span>}
39+
</div>
40+
<div>
41+
<div className="search-result">
42+
{hits && hits.length > 0 ? (
43+
hits.map((product) => (
44+
<li key={product.objectID} className="product">
45+
<span className="product-name">{product.name}</span>
46+
{product.shortDescription && (
47+
<>
48+
<br />
49+
<span className="product-description">
50+
{product.shortDescription}
51+
</span>
52+
</>
53+
)}
54+
<br />
55+
<span className="product-price">${product.salePrice}</span>
56+
</li>
57+
))
58+
) : (
59+
<h3>No products found!</h3>
60+
)}
61+
</div>
62+
{hasNextPage && (
63+
<div className="search-more" onClick={() => fetchNextPage()}>
64+
more
65+
</div>
66+
)}
67+
{isFetchingNextPage && (
68+
<div className="search-status">Fetching next page...</div>
69+
)}
70+
</div>
71+
</div>
72+
);
73+
}

0 commit comments

Comments
 (0)