Skip to content
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

feat: expose querykey getter and fix some querykey stuff #3302

Merged
merged 51 commits into from Dec 23, 2022
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
5392463
1
juliusmarminge Nov 27, 2022
8638767
Merge branch 'main' into julius/querykeys
juliusmarminge Nov 27, 2022
bc702cc
2
juliusmarminge Nov 27, 2022
5b55386
add some tests
juliusmarminge Nov 27, 2022
2711978
failing test
juliusmarminge Nov 27, 2022
30dcc40
simplify
juliusmarminge Nov 27, 2022
d77f3c8
going places
juliusmarminge Nov 27, 2022
36ffd96
docs
juliusmarminge Nov 27, 2022
0a97a6b
more docs
juliusmarminge Nov 27, 2022
217db37
revert example
juliusmarminge Nov 27, 2022
964da9c
docs 3
juliusmarminge Nov 27, 2022
90a9173
add test
juliusmarminge Nov 27, 2022
dc92dcf
fix test
juliusmarminge Nov 27, 2022
5813e19
restructure
juliusmarminge Nov 27, 2022
366107d
revert lock
juliusmarminge Nov 27, 2022
c1d4497
better brackets
juliusmarminge Nov 27, 2022
c909673
better docs
juliusmarminge Nov 27, 2022
4efa3a8
fixy
juliusmarminge Nov 27, 2022
778859d
please not now docu
juliusmarminge Nov 27, 2022
7770be8
imports
juliusmarminge Nov 27, 2022
e9f03e1
Merge branch 'main' into julius/querykeys
juliusmarminge Dec 4, 2022
cca2d30
move it to trpc object instead
juliusmarminge Dec 5, 2022
8b937df
docs
juliusmarminge Dec 5, 2022
c9b59bd
simplify test setup
juliusmarminge Dec 5, 2022
44179fd
make optional
juliusmarminge Dec 5, 2022
2d25187
add test outside react
juliusmarminge Dec 5, 2022
d06701a
add example
juliusmarminge Dec 5, 2022
4b4e12f
fix
juliusmarminge Dec 5, 2022
377e271
fix2
juliusmarminge Dec 5, 2022
c8b8ee8
docs and remove example
juliusmarminge Dec 16, 2022
cdc5808
Merge branch 'main' into julius/querykeys
juliusmarminge Dec 16, 2022
dd8062e
revert downgrade of docusaurus
juliusmarminge Dec 16, 2022
04d5333
Merge branch 'main' into julius/querykeys
juliusmarminge Dec 16, 2022
c92eb39
Merge branch 'main' into julius/querykeys
juliusmarminge Dec 16, 2022
c1b162e
qc -> queryClient
juliusmarminge Dec 16, 2022
c8e3ed7
mby???
juliusmarminge Dec 16, 2022
0e519e2
patch querykey
juliusmarminge Dec 22, 2022
60afce2
fix invalidate
juliusmarminge Dec 22, 2022
72b5ab6
fix old
juliusmarminge Dec 22, 2022
6f195da
regression tests
juliusmarminge Dec 22, 2022
d60dea3
testid
juliusmarminge Dec 22, 2022
f566339
Merge remote-tracking branch 'origin/main' into julius/querykeys
juliusmarminge Dec 22, 2022
5adc7ec
fix
juliusmarminge Dec 22, 2022
957a78c
interop
juliusmarminge Dec 22, 2022
f025343
Merge branch 'main' into julius/querykeys
juliusmarminge Dec 22, 2022
3ceba17
disable interop
juliusmarminge Dec 22, 2022
05f5c8d
comment
juliusmarminge Dec 22, 2022
88b8052
1 more test
juliusmarminge Dec 22, 2022
943fdeb
fix the interop stuff
juliusmarminge Dec 22, 2022
bb26bc1
eeh
juliusmarminge Dec 22, 2022
1396478
Merge branch 'main' into julius/querykeys
kodiakhq[bot] Dec 23, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 13 additions & 0 deletions examples/tanstack-router/README.md
@@ -0,0 +1,13 @@
# A minimal React tRPC example using @tanstack/react-router
Copy link
Member Author

Choose a reason for hiding this comment

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

Just a playground for seeing the usage - I don't think we should keep this but instead contribute to https://github.com/TanStack/router/tree/beta/examples/react/with-trpc-react-query

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

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

Maybe just remove the example for now then and revisit later?


Requires node 18 (for global fetch).

## Playing around

```bash
npm i
npm run dev
```

Try editing the ts files to see the type checking in action :)

13 changes: 13 additions & 0 deletions examples/tanstack-router/client/index.html
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://cdn.tailwindcss.com"></script>
<title>tRPC + @tanstack/router</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
25 changes: 25 additions & 0 deletions examples/tanstack-router/client/package.json
@@ -0,0 +1,25 @@
{
"name": "@examples/tanstack-router-client",
"private": true,
"version": "10.4.3",
"type": "module",
"scripts": {
"dev": "vite"
},
"dependencies": {
"@tanstack/react-query": "^4.3.8",
"@tanstack/react-router": "0.0.1-beta.29",
"@trpc/client": "^10.4.3",
"@trpc/react-query": "^10.4.3",
"@trpc/server": "^10.4.3",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.0.9",
"@types/react-dom": "^18.0.5",
"@vitejs/plugin-react": "^2.1.0",
"typescript": "^4.8.3",
"vite": "^3.1.3"
}
}
13 changes: 13 additions & 0 deletions examples/tanstack-router/client/src/main.tsx
@@ -0,0 +1,13 @@
import { RouterProvider } from '@tanstack/react-router';
import React from 'react';
import ReactDOM from 'react-dom/client';
import { router } from './utils/router';
import { TRPCProvider } from './utils/trpc';

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<TRPCProvider>
<RouterProvider router={router} />
</TRPCProvider>
</React.StrictMode>,
);
145 changes: 145 additions & 0 deletions examples/tanstack-router/client/src/utils/router.tsx
@@ -0,0 +1,145 @@
/* eslint-disable react-hooks/rules-of-hooks */
Copy link
Member Author

Choose a reason for hiding this comment

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

Suggested change
/* eslint-disable react-hooks/rules-of-hooks */
/**
* @see https://tanstack.com/router/v1/docs/examples/react/basic
**/
/* eslint-disable react-hooks/rules-of-hooks */

import {
Link,
Outlet,
createReactRouter,
createRouteConfig,
useMatch,
} from '@tanstack/react-router';
import { getPostById, getPosts } from '../../../server/fetchers';
juliusmarminge marked this conversation as resolved.
Show resolved Hide resolved
import { queryClient, trpc } from './trpc';

const rootRoute = createRouteConfig({
component: () => {
return (
<>
<div className="p-2 flex gap-2 text-lg">
<Link
to="/"
activeProps={{
className: 'font-bold',
}}
activeOptions={{ exact: true }}
>
Home
</Link>{' '}
<Link
to="/posts"
activeProps={{
className: 'font-bold',
}}
>
Posts
</Link>
</div>
<hr />
<Outlet /> {/* Start rendering router matches */}
</>
);
},
});

const indexRoute = rootRoute.createRoute({
path: '/',
component: () => {
const hello = trpc.hello.useQuery();
if (!hello.data) return <p>Loading...</p>;
return <div>{hello.data}</div>;
},
});

const postsRoute = rootRoute.createRoute({
path: 'posts',
loaderMaxAge: 0,
errorComponent: () => 'Oh crap!',
loader: async () => {
const postKey = trpc.post.all.getQueryKey(undefined, 'query');

queryClient.getQueryData(postKey) ??
(await queryClient.prefetchQuery(postKey, getPosts));
return {};
},

component: () => {
const postsQuery = trpc.post.all.useQuery();
Copy link
Member Author

Choose a reason for hiding this comment

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

this is how i thought it'd be useful


return (
<div className="p-2 flex gap-2">
<ul className="list-disc pl-4">
{postsQuery.data?.map((post) => {
return (
<li key={post.id} className="whitespace-nowrap">
<Link
to={postRoute.id}
params={{
postId: post.id,
}}
className="block py-1 text-blue-800 hover:text-blue-600"
activeProps={{ className: 'text-black font-bold' }}
>
<div>{post.title.substring(0, 20)}</div>
</Link>
</li>
);
})}
</ul>
<hr />
<Outlet />
</div>
);
},
});

const postsIndexRoute = postsRoute.createRoute({
path: '/',

component: () => {
return (
<>
<div>Select a post.</div>
</>
);
},
});

const postRoute = postsRoute.createRoute({
path: '$postId',
loader: async ({ params }) => {
const postKey = trpc.post.byId.getQueryKey({ id: params.postId }, 'query');
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't we be able to use .prefetch here? Or is it b/c it's only on the context? Is there a way to make that happen?

Copy link
Member Author

Choose a reason for hiding this comment

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

That doesn't work since this is outside the react tree and we don't have our context stuff here. Might be possible to do something similar to the SSG helpers (or maybe they even work?)

Copy link
Member

Choose a reason for hiding this comment

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

Hmmmmmm..... I don't like embedding this example when the DX is not optimal


queryClient.getQueryData(postKey) ??
juliusmarminge marked this conversation as resolved.
Show resolved Hide resolved
(await queryClient.prefetchQuery(postKey, () =>
getPostById(params.postId),
));
juliusmarminge marked this conversation as resolved.
Show resolved Hide resolved

return {};
},

component: () => {
const { params } = useMatch(postRoute.id);
const postQuery = trpc.post.byId.useQuery({ id: params.postId });

return (
<div className="space-y-2">
<h4 className="text-xl font-bold underline">{postQuery.data?.title}</h4>
</div>
);
},
});

const routeConfig = rootRoute.addChildren([
indexRoute,
postsRoute.addChildren([postsIndexRoute, postRoute]),
]);

// Set up a ReactRouter instance
export const router = createReactRouter({
routeConfig,
defaultPreload: 'intent',
});

declare module '@tanstack/react-router' {
interface RegisterRouter {
router: typeof router;
}
}
40 changes: 40 additions & 0 deletions examples/tanstack-router/client/src/utils/trpc.tsx
@@ -0,0 +1,40 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { httpBatchLink } from '@trpc/client';
import { createTRPCReact } from '@trpc/react-query';
import React from 'react';
import type { AppRouter } from '../../../server';

/**
* Typesafe hooks
*/
export const trpc = createTRPCReact<AppRouter>();

/**
* Create a QueryClient outside of the app,
* so we can use it for route loaders
*/
export const queryClient = new QueryClient();

/**
* A wrapper for your app that provides the TRPC context.
* Use only in _app.tsx
*/
export const TRPCProvider: React.FC<{ children: React.ReactNode }> = ({
children,
}) => {
const [trpcClient] = React.useState(() =>
trpc.createClient({
links: [
httpBatchLink({
url: 'http://localhost:2023',
}),
],
}),
);

return (
<trpc.Provider client={trpcClient} queryClient={queryClient}>
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
</trpc.Provider>
);
};
21 changes: 21 additions & 0 deletions examples/tanstack-router/client/tsconfig.json
@@ -0,0 +1,21 @@
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"allowJs": false,
"skipLibCheck": true,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"moduleResolution": "Node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"types": ["vite/client"]
},
"include": ["src", "vite.config.ts"]
}
13 changes: 13 additions & 0 deletions examples/tanstack-router/client/vite.config.ts
@@ -0,0 +1,13 @@
import react from '@vitejs/plugin-react';
import { defineConfig } from 'vite';

// https://vitejs.dev/config/
export default defineConfig({
server: {
port: 3000,
},
preview: {
port: 3000,
},
plugins: [react()],
});
17 changes: 17 additions & 0 deletions examples/tanstack-router/package.json
@@ -0,0 +1,17 @@
{
"name": "@examples/tanstack-router",
"private": true,
"version": "10.4.3",
"workspaces": [
"client",
"server"
],
"scripts": {
"dev:client": "npm run dev -w client",
"dev:server": "npm run dev -w server",
"dev": "run-p dev:*"
},
"devDependencies": {
"npm-run-all": "^4.1.5"
}
}
18 changes: 18 additions & 0 deletions examples/tanstack-router/server/fetchers.ts
@@ -0,0 +1,18 @@
const db = {
posts: [
{ id: '1', title: 'hello world' },
{ id: '2', title: 'foo bar' },
],
};

export const getPosts = async () => {
// simulate slow db
await new Promise((res) => setTimeout(res, 1000));
return db.posts;
};

export const getPostById = async (id: string) => {
// simulate slow db
await new Promise((res) => setTimeout(res, 1000));
return db.posts.find((post) => post.id === id);
};
52 changes: 52 additions & 0 deletions examples/tanstack-router/server/index.ts
@@ -0,0 +1,52 @@
/**
* This is the API-handler of your app that contains all your API routes.
* On a bigger app, you will probably want to split this file up into multiple files.
*/
import { initTRPC } from '@trpc/server';
import { createHTTPHandler } from '@trpc/server/adapters/standalone';
import http from 'http';
import { z } from 'zod';
import { getPostById, getPosts } from './fetchers';

const t = initTRPC.create();

const publicProcedure = t.procedure;
const router = t.router;

const appRouter = router({
hello: publicProcedure.query(() => 'Hello world!'),
post: router({
all: publicProcedure.query(async () => {
return await getPosts();
}),
byId: publicProcedure
.input(z.object({ id: z.string() }))
.query(async ({ input }) => {
return await getPostById(input.id);
}),
}),
});

// export only the type definition of the API
// None of the actual implementation is exposed to the client
export type AppRouter = typeof appRouter;

// create handler
const handler = createHTTPHandler({
router: appRouter,
createContext: () => ({}),
});

const server = http.createServer((req, res) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Request-Method', '*');
res.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET');
res.setHeader('Access-Control-Allow-Headers', '*');
if (req.method === 'OPTIONS') {
res.writeHead(200);
return res.end();
}
handler(req, res);
});

server.listen(2023);
17 changes: 17 additions & 0 deletions examples/tanstack-router/server/package.json
@@ -0,0 +1,17 @@
{
"name": "@examples/tanstack-router-server",
"version": "10.4.3",
"private": true,
"scripts": {
"dev": "tsx watch index.ts"
},
"dependencies": {
"@trpc/server": "^10.4.3",
"zod": "^3.0.0"
},
"devDependencies": {
"@types/node": "^18.7.20",
"tsx": "^3.9.0",
"typescript": "^4.8.3"
}
}