-
-
Notifications
You must be signed in to change notification settings - Fork 134
feat(examples): add AI-powered search example #114
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
denis-shvets
wants to merge
8
commits into
TanStack:main
Choose a base branch
from
denis-shvets:ts-react-search
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
b5a5120
feat(examples): add AI-powered search example
denis-shvets 73f1773
feat(examples/ts-react-search): add navigation component to hero section
denis-shvets eff0a2e
refactor(navigation): simplify route references in Navigation component
denis-shvets e1c888b
refactor(routes): restructure API search route into directory
denis-shvets 10a444e
feat(examples): integrate TanStack DB for client-side data management
denis-shvets ed53e24
feat(examples): update search API to use server-sent events streaming
denis-shvets ca00bfb
chore(deps): update TanStack Router and related dependencies
denis-shvets 9e80da9
fix(ts-react-search): correct hook dependency, filter id typo, and fr…
denis-shvets File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| { | ||
| "projectName": "ts-react-search", | ||
| "mode": "file-router", | ||
| "typescript": true, | ||
| "tailwind": true, | ||
| "packageManager": "pnpm", | ||
| "addOnOptions": {}, | ||
| "git": true, | ||
| "version": 1, | ||
| "framework": "vite-react", | ||
| "chosenAddOns": ["nitro", "start"] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| node_modules | ||
| .DS_Store | ||
| dist | ||
| dist-ssr | ||
| *.local | ||
| count.txt | ||
| .env | ||
| .nitro | ||
| .tanstack | ||
| .wrangler | ||
| .output | ||
| .vinxi | ||
| todos.json |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| { | ||
| "files.watcherExclude": { | ||
| "**/routeTree.gen.ts": true | ||
| }, | ||
| "search.exclude": { | ||
| "**/routeTree.gen.ts": true | ||
| }, | ||
| "files.readonlyInclude": { | ||
| "**/routeTree.gen.ts": true | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,287 @@ | ||
| Welcome to your new TanStack app! | ||
|
|
||
| # Getting Started | ||
|
|
||
| To run this application: | ||
|
|
||
| ```bash | ||
| pnpm install | ||
| pnpm start | ||
denis-shvets marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ``` | ||
denis-shvets marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| # Building For Production | ||
|
|
||
| To build this application for production: | ||
|
|
||
| ```bash | ||
| pnpm build | ||
| ``` | ||
|
|
||
| ## Testing | ||
|
|
||
| This project uses [Vitest](https://vitest.dev/) for testing. You can run the tests with: | ||
|
|
||
| ```bash | ||
| pnpm test | ||
| ``` | ||
|
|
||
| ## Styling | ||
|
|
||
| This project uses [Tailwind CSS](https://tailwindcss.com/) for styling. | ||
|
|
||
| ## Routing | ||
|
|
||
| This project uses [TanStack Router](https://tanstack.com/router). The initial setup is a file based router. Which means that the routes are managed as files in `src/routes`. | ||
denis-shvets marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| ### Adding A Route | ||
|
|
||
| To add a new route to your application just add another a new file in the `./src/routes` directory. | ||
|
|
||
| TanStack will automatically generate the content of the route file for you. | ||
|
|
||
| Now that you have two routes you can use a `Link` component to navigate between them. | ||
|
|
||
| ### Adding Links | ||
|
|
||
| To use SPA (Single Page Application) navigation you will need to import the `Link` component from `@tanstack/react-router`. | ||
|
|
||
| ```tsx | ||
| import { Link } from '@tanstack/react-router' | ||
| ``` | ||
|
|
||
| Then anywhere in your JSX you can use it like so: | ||
|
|
||
| ```tsx | ||
| <Link to="/about">About</Link> | ||
| ``` | ||
|
|
||
| This will create a link that will navigate to the `/about` route. | ||
|
|
||
| More information on the `Link` component can be found in the [Link documentation](https://tanstack.com/router/v1/docs/framework/react/api/router/linkComponent). | ||
|
|
||
| ### Using A Layout | ||
|
|
||
| In the File Based Routing setup the layout is located in `src/routes/__root.tsx`. Anything you add to the root route will appear in all the routes. The route content will appear in the JSX where you use the `<Outlet />` component. | ||
|
|
||
| Here is an example layout that includes a header: | ||
|
|
||
| ```tsx | ||
| import { Outlet, createRootRoute } from '@tanstack/react-router' | ||
| import { TanStackRouterDevtools } from '@tanstack/react-router-devtools' | ||
|
|
||
| import { Link } from '@tanstack/react-router' | ||
|
|
||
| export const Route = createRootRoute({ | ||
| component: () => ( | ||
| <> | ||
| <header> | ||
| <nav> | ||
| <Link to="/">Home</Link> | ||
| <Link to="/about">About</Link> | ||
| </nav> | ||
| </header> | ||
| <Outlet /> | ||
| <TanStackRouterDevtools /> | ||
| </> | ||
| ), | ||
| }) | ||
| ``` | ||
|
|
||
| The `<TanStackRouterDevtools />` component is not required so you can remove it if you don't want it in your layout. | ||
|
|
||
| More information on layouts can be found in the [Layouts documentation](https://tanstack.com/router/latest/docs/framework/react/guide/routing-concepts#layouts). | ||
|
|
||
| ## Data Fetching | ||
|
|
||
| There are multiple ways to fetch data in your application. You can use TanStack Query to fetch data from a server. But you can also use the `loader` functionality built into TanStack Router to load the data for a route before it's rendered. | ||
|
|
||
| For example: | ||
|
|
||
| ```tsx | ||
| const peopleRoute = createRoute({ | ||
| getParentRoute: () => rootRoute, | ||
| path: '/people', | ||
| loader: async () => { | ||
| const response = await fetch('https://swapi.dev/api/people') | ||
| return response.json() as Promise<{ | ||
| results: { | ||
| name: string | ||
| }[] | ||
| }> | ||
| }, | ||
| component: () => { | ||
| const data = peopleRoute.useLoaderData() | ||
| return ( | ||
| <ul> | ||
| {data.results.map((person) => ( | ||
| <li key={person.name}>{person.name}</li> | ||
| ))} | ||
| </ul> | ||
| ) | ||
| }, | ||
| }) | ||
| ``` | ||
|
|
||
| Loaders simplify your data fetching logic dramatically. Check out more information in the [Loader documentation](https://tanstack.com/router/latest/docs/framework/react/guide/data-loading#loader-parameters). | ||
denis-shvets marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| ### React-Query | ||
|
|
||
| React-Query is an excellent addition or alternative to route loading and integrating it into you application is a breeze. | ||
denis-shvets marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| First add your dependencies: | ||
|
|
||
| ```bash | ||
| pnpm add @tanstack/react-query @tanstack/react-query-devtools | ||
| ``` | ||
|
|
||
| Next we'll need to create a query client and provider. We recommend putting those in `main.tsx`. | ||
|
|
||
| ```tsx | ||
| import { QueryClient, QueryClientProvider } from '@tanstack/react-query' | ||
|
|
||
| // ... | ||
|
|
||
| const queryClient = new QueryClient() | ||
|
|
||
| // ... | ||
|
|
||
| if (!rootElement.innerHTML) { | ||
| const root = ReactDOM.createRoot(rootElement) | ||
|
|
||
| root.render( | ||
| <QueryClientProvider client={queryClient}> | ||
| <RouterProvider router={router} /> | ||
| </QueryClientProvider>, | ||
| ) | ||
| } | ||
| ``` | ||
|
|
||
| You can also add TanStack Query Devtools to the root route (optional). | ||
|
|
||
| ```tsx | ||
| import { ReactQueryDevtools } from '@tanstack/react-query-devtools' | ||
|
|
||
| const rootRoute = createRootRoute({ | ||
| component: () => ( | ||
| <> | ||
| <Outlet /> | ||
| <ReactQueryDevtools buttonPosition="top-right" /> | ||
| <TanStackRouterDevtools /> | ||
| </> | ||
| ), | ||
| }) | ||
| ``` | ||
|
|
||
| Now you can use `useQuery` to fetch your data. | ||
|
|
||
| ```tsx | ||
| import { useQuery } from '@tanstack/react-query' | ||
|
|
||
| import './App.css' | ||
|
|
||
| function App() { | ||
| const { data } = useQuery({ | ||
| queryKey: ['people'], | ||
| queryFn: () => | ||
| fetch('https://swapi.dev/api/people') | ||
| .then((res) => res.json()) | ||
| .then((data) => data.results as { name: string }[]), | ||
| initialData: [], | ||
| }) | ||
|
|
||
| return ( | ||
| <div> | ||
| <ul> | ||
| {data.map((person) => ( | ||
| <li key={person.name}>{person.name}</li> | ||
| ))} | ||
| </ul> | ||
| </div> | ||
| ) | ||
| } | ||
|
|
||
| export default App | ||
| ``` | ||
|
|
||
| You can find out everything you need to know on how to use React-Query in the [React-Query documentation](https://tanstack.com/query/latest/docs/framework/react/overview). | ||
|
|
||
| ## State Management | ||
|
|
||
| Another common requirement for React applications is state management. There are many options for state management in React. TanStack Store provides a great starting point for your project. | ||
|
|
||
| First you need to add TanStack Store as a dependency: | ||
|
|
||
| ```bash | ||
| pnpm add @tanstack/store | ||
| ``` | ||
|
|
||
| Now let's create a simple counter in the `src/App.tsx` file as a demonstration. | ||
|
|
||
| ```tsx | ||
| import { useStore } from '@tanstack/react-store' | ||
| import { Store } from '@tanstack/store' | ||
| import './App.css' | ||
|
|
||
| const countStore = new Store(0) | ||
|
|
||
| function App() { | ||
| const count = useStore(countStore) | ||
| return ( | ||
| <div> | ||
| <button onClick={() => countStore.setState((n) => n + 1)}> | ||
| Increment - {count} | ||
| </button> | ||
| </div> | ||
| ) | ||
| } | ||
|
|
||
| export default App | ||
| ``` | ||
|
|
||
| One of the many nice features of TanStack Store is the ability to derive state from other state. That derived state will update when the base state updates. | ||
|
|
||
| Let's check this out by doubling the count using derived state. | ||
|
|
||
| ```tsx | ||
| import { useStore } from '@tanstack/react-store' | ||
| import { Store, Derived } from '@tanstack/store' | ||
| import './App.css' | ||
|
|
||
| const countStore = new Store(0) | ||
|
|
||
| const doubledStore = new Derived({ | ||
| fn: () => countStore.state * 2, | ||
| deps: [countStore], | ||
| }) | ||
| doubledStore.mount() | ||
|
|
||
| function App() { | ||
| const count = useStore(countStore) | ||
| const doubledCount = useStore(doubledStore) | ||
|
|
||
| return ( | ||
| <div> | ||
| <button onClick={() => countStore.setState((n) => n + 1)}> | ||
| Increment - {count} | ||
| </button> | ||
| <div>Doubled - {doubledCount}</div> | ||
| </div> | ||
| ) | ||
| } | ||
|
|
||
| export default App | ||
| ``` | ||
|
|
||
| We use the `Derived` class to create a new store that is derived from another store. The `Derived` class has a `mount` method that will start the derived store updating. | ||
|
|
||
| Once we've created the derived store we can use it in the `App` component just like we would any other store using the `useStore` hook. | ||
|
|
||
| You can find out everything you need to know on how to use TanStack Store in the [TanStack Store documentation](https://tanstack.com/store/latest). | ||
|
|
||
| # Demo files | ||
|
|
||
| Files prefixed with `demo` can be safely deleted. They are there to provide a starting point for you to play around with the features you've installed. | ||
|
|
||
| # Learn More | ||
|
|
||
| You can learn more about all of the offerings from TanStack in the [TanStack documentation](https://tanstack.com). | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| { | ||
| "name": "ts-react-search", | ||
| "private": true, | ||
| "type": "module", | ||
| "scripts": { | ||
| "dev": "vite dev --port 3000", | ||
| "build": "vite build", | ||
| "serve": "vite preview", | ||
| "test": "exit 0" | ||
denis-shvets marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| }, | ||
| "dependencies": { | ||
| "@radix-ui/react-slot": "^1.2.4", | ||
| "@tailwindcss/vite": "^4.1.18", | ||
| "@tanstack/ai": "workspace:*", | ||
| "@tanstack/ai-openai": "workspace:*", | ||
| "@tanstack/ai-react": "workspace:*", | ||
| "@tanstack/query-db-collection": "^1.0.25", | ||
| "@tanstack/react-db": "^0.1.72", | ||
| "@tanstack/react-devtools": "^0.8.2", | ||
| "@tanstack/react-query": "^5.90.12", | ||
| "@tanstack/react-router": "^1.158.4", | ||
| "@tanstack/react-router-devtools": "^1.158.4", | ||
| "@tanstack/react-router-ssr-query": "^1.158.4", | ||
| "@tanstack/react-start": "^1.159.0", | ||
| "@tanstack/router-plugin": "^1.158.4", | ||
| "@tanstack/zod-adapter": "^1.162.2", | ||
| "class-variance-authority": "^0.7.1", | ||
| "clsx": "^2.1.1", | ||
| "lucide-react": "^0.561.0", | ||
| "nitro": "3.0.1-alpha.2", | ||
| "radix-ui": "^1.4.3", | ||
| "react": "^19.2.3", | ||
| "react-day-picker": "^9.13.2", | ||
| "react-dom": "^19.2.3", | ||
| "tailwind-merge": "^3.5.0", | ||
| "tailwindcss": "^4.1.18", | ||
| "tw-animate-css": "^1.4.0", | ||
| "vite-tsconfig-paths": "^5.1.4", | ||
| "zod": "^4.2.0" | ||
| }, | ||
| "devDependencies": { | ||
| "@tanstack/devtools-vite": "^0.3.11", | ||
| "@testing-library/dom": "^10.4.1", | ||
| "@testing-library/react": "^16.3.0", | ||
| "@types/node": "^24.10.1", | ||
| "@types/react": "^19.2.7", | ||
| "@types/react-dom": "^19.2.3", | ||
| "@vitejs/plugin-react": "^5.1.2", | ||
| "jsdom": "^27.2.0", | ||
| "typescript": "5.9.3", | ||
| "vite": "^7.2.7", | ||
| "vitest": "^4.0.14", | ||
| "web-vitals": "^5.1.0" | ||
| } | ||
| } | ||
Empty file.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.