@imfusion/web-ui 0.5.1-dev.18.g81350f83 → 0.5.1-dev.19.g11b806f9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -12,7 +12,6 @@ src/
|
|
|
12
12
|
<topic>.ts # queryOptions / mutationOptions
|
|
13
13
|
query-key.ts # key factory, topic as the first segment
|
|
14
14
|
types.ts # Zod schemas + z.infer types
|
|
15
|
-
use-<thing>.ts # hooks wrapping the options for components
|
|
16
15
|
http/ # transport: client, error normalisation — the only transport-aware place
|
|
17
16
|
```
|
|
18
17
|
|
|
@@ -65,19 +64,8 @@ export const userQueryOptions = () =>
|
|
|
65
64
|
});
|
|
66
65
|
```
|
|
67
66
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
```ts
|
|
71
|
-
// api/user/use-user.ts
|
|
72
|
-
import { useSuspenseQuery } from "@tanstack/react-query";
|
|
73
|
-
|
|
74
|
-
import { userQueryOptions } from "./user";
|
|
75
|
-
|
|
76
|
-
export const useUser = () => useSuspenseQuery(userQueryOptions());
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
The options and their hook can start colocated in one file — options right beside the hook that consumes them — and split
|
|
80
|
-
into separate files when the topic's complexity demands it.
|
|
67
|
+
Components consume query options directly with `useSuspenseQuery` (prefetched routes) or `useQuery` (secondary data). No
|
|
68
|
+
wrapper hooks — the options function is the reusable unit.
|
|
81
69
|
|
|
82
70
|
Mutations follow the same shape with `mutationOptions`, the dirtied topic first in the `mutationKey`:
|
|
83
71
|
|
|
@@ -90,8 +78,86 @@ export const updateUserMutationOptions = () =>
|
|
|
90
78
|
});
|
|
91
79
|
```
|
|
92
80
|
|
|
93
|
-
|
|
94
|
-
|
|
81
|
+
The root route types the router context so every loader can reach the query client via DI:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
// routes/__root.tsx
|
|
85
|
+
import { Outlet, createRootRouteWithContext } from "@tanstack/react-router";
|
|
86
|
+
import type { QueryClient } from "@tanstack/react-query";
|
|
87
|
+
|
|
88
|
+
interface RouterContext {
|
|
89
|
+
queryClient: QueryClient;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export const Route = createRootRouteWithContext<RouterContext>()({
|
|
93
|
+
component: () => <Outlet />
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The router is created with that context filled in:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
// router.ts
|
|
101
|
+
import { createRouter } from "@tanstack/react-router";
|
|
102
|
+
import { routeTree } from "./routeTree.gen";
|
|
103
|
+
import { createQueryClient } from "./query-client";
|
|
104
|
+
|
|
105
|
+
const queryClient = createQueryClient();
|
|
106
|
+
|
|
107
|
+
export const router = createRouter({
|
|
108
|
+
routeTree,
|
|
109
|
+
context: { queryClient }
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
A route prefetches in the `loader`, reads with `useSuspenseQuery`, and provides a `pendingComponent`; errors bubble to the
|
|
114
|
+
nearest `errorComponent`:
|
|
115
|
+
|
|
116
|
+
```tsx
|
|
117
|
+
// routes/me.tsx
|
|
118
|
+
import { createFileRoute } from "@tanstack/react-router";
|
|
119
|
+
import { useSuspenseQuery } from "@tanstack/react-query";
|
|
120
|
+
|
|
121
|
+
import { userQueryOptions } from "#/api/user/user";
|
|
122
|
+
|
|
123
|
+
export const Route = createFileRoute("/me")({
|
|
124
|
+
loader: ({ context }) => context.queryClient.ensureQueryData(userQueryOptions()),
|
|
125
|
+
pendingComponent: () => <p>Loading…</p>,
|
|
126
|
+
component: MePage
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
function MePage() {
|
|
130
|
+
const { data: user } = useSuspenseQuery(userQueryOptions());
|
|
131
|
+
return <h1>{user.name}</h1>;
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Mutations use `useMutation` with the options factory. Manual invalidation is unnecessary when automatic invalidation is on
|
|
136
|
+
(see below):
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
// components/user-settings.tsx
|
|
140
|
+
import { useMutation } from "@tanstack/react-query";
|
|
141
|
+
import { useSuspenseQuery } from "@tanstack/react-query";
|
|
142
|
+
|
|
143
|
+
import { userQueryOptions, updateUserMutationOptions } from "#/api/user/user";
|
|
144
|
+
|
|
145
|
+
function UserSettings() {
|
|
146
|
+
const { data: user } = useSuspenseQuery(userQueryOptions());
|
|
147
|
+
const updateUser = useMutation(updateUserMutationOptions());
|
|
148
|
+
|
|
149
|
+
return (
|
|
150
|
+
<form
|
|
151
|
+
onSubmit={e => {
|
|
152
|
+
e.preventDefault();
|
|
153
|
+
updateUser.mutate({ name: "New Name" });
|
|
154
|
+
}}
|
|
155
|
+
>
|
|
156
|
+
<input defaultValue={user.name} />
|
|
157
|
+
</form>
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
```
|
|
95
161
|
|
|
96
162
|
## Automatic invalidation
|
|
97
163
|
|