@modelence/react-query 1.0.0 → 1.0.1

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/README.md CHANGED
@@ -10,7 +10,7 @@ npm i @modelence/react-query @tanstack/react-query
10
10
 
11
11
  ## Overview
12
12
 
13
- This package provides `getQueryOptions` and `getMutationOptions` factory functions that can be used with TanStack Query's native `useQuery` and `useMutation` hooks. This approach, recommended by TanStack, gives you direct access to TanStack Query's full API while providing Modelence-specific query configurations.
13
+ This package provides `modelenceQuery` and `modelenceMutation` factory functions that can be used with TanStack Query's native `useQuery` and `useMutation` hooks. This approach, recommended by TanStack, gives you direct access to TanStack Query's full API while providing Modelence-specific query configurations.
14
14
 
15
15
  ## Usage
16
16
 
@@ -18,11 +18,11 @@ This package provides `getQueryOptions` and `getMutationOptions` factory functio
18
18
 
19
19
  ```tsx
20
20
  import { useQuery } from '@tanstack/react-query';
21
- import { getQueryOptions } from '@modelence/react-query';
21
+ import { modelenceQuery } from '@modelence/react-query';
22
22
 
23
23
  function TodoList() {
24
24
  const { data, isPending, error } = useQuery(
25
- getQueryOptions('todo.getAll', { limit: 10 })
25
+ modelenceQuery('todo.getAll', { limit: 10 })
26
26
  );
27
27
 
28
28
  if (isPending) return <div>Loading...</div>;
@@ -42,13 +42,13 @@ function TodoList() {
42
42
 
43
43
  ```tsx
44
44
  import { useMutation, useQueryClient } from '@tanstack/react-query';
45
- import { getMutationOptions } from '@modelence/react-query';
45
+ import { modelenceMutation } from '@modelence/react-query';
46
46
 
47
47
  function CreateTodo() {
48
48
  const queryClient = useQueryClient();
49
49
 
50
50
  const { mutate: createTodo, isPending } = useMutation({
51
- ...getMutationOptions('todo.create'),
51
+ ...modelenceMutation('todo.create'),
52
52
  onSuccess: () => {
53
53
  // Invalidate and refetch todos
54
54
  queryClient.invalidateQueries({ queryKey: ['todo.getAll'] });
@@ -72,11 +72,11 @@ function CreateTodo() {
72
72
 
73
73
  ```tsx
74
74
  import { useQuery } from '@tanstack/react-query';
75
- import { getQueryOptions } from '@modelence/react-query';
75
+ import { modelenceQuery } from '@modelence/react-query';
76
76
 
77
77
  function TodoDetail({ id }: { id: string }) {
78
78
  const { data: todo } = useQuery({
79
- ...getQueryOptions('todo.getById', { id }),
79
+ ...modelenceQuery('todo.getById', { id }),
80
80
  enabled: !!id, // Only run query if id exists
81
81
  staleTime: 5 * 60 * 1000, // 5 minutes
82
82
  refetchOnWindowFocus: false,
@@ -90,11 +90,11 @@ function TodoDetail({ id }: { id: string }) {
90
90
 
91
91
  ```tsx
92
92
  import { useMutation } from '@tanstack/react-query';
93
- import { getMutationOptions } from '@modelence/react-query';
93
+ import { modelenceMutation } from '@modelence/react-query';
94
94
 
95
95
  function UpdateTodo({ todoId }: { todoId: string }) {
96
96
  const { mutate: updateTodo } = useMutation({
97
- ...getMutationOptions('todo.update', { id: todoId }), // Default args
97
+ ...modelenceMutation('todo.update', { id: todoId }), // Default args
98
98
  onSuccess: (data) => {
99
99
  console.log('Todo updated:', data);
100
100
  },
@@ -112,7 +112,7 @@ function UpdateTodo({ todoId }: { todoId: string }) {
112
112
 
113
113
  ```tsx
114
114
  import { useQueryClient } from '@tanstack/react-query';
115
- import { createQueryKey, getQueryOptions } from '@modelence/react-query';
115
+ import { createQueryKey, modelenceQuery } from '@modelence/react-query';
116
116
 
117
117
  function TodoActions() {
118
118
  const queryClient = useQueryClient();
@@ -125,7 +125,7 @@ function TodoActions() {
125
125
 
126
126
  const prefetchTodo = (id: string) => {
127
127
  queryClient.prefetchQuery({
128
- ...getQueryOptions('todo.getById', { id }),
128
+ ...modelenceQuery('todo.getById', { id }),
129
129
  staleTime: 10 * 60 * 1000, // 10 minutes
130
130
  });
131
131
  };
@@ -138,77 +138,3 @@ function TodoActions() {
138
138
  );
139
139
  }
140
140
  ```
141
-
142
- ## API Reference
143
-
144
- ### `getQueryOptions<T>(methodName, args?)`
145
-
146
- Creates a query configuration object for use with TanStack Query's `useQuery`.
147
-
148
- **Parameters:**
149
- - `methodName` (string): The Modelence method name (e.g., 'todo.getAll')
150
- - `args` (object, optional): Arguments to pass to the method
151
-
152
- **Returns:** Query configuration object with `queryKey` and `queryFn`
153
-
154
- ### `getMutationOptions<T, TVariables>(methodName, defaultArgs?)`
155
-
156
- Creates a mutation configuration object for use with TanStack Query's `useMutation`.
157
-
158
- **Parameters:**
159
- - `methodName` (string): The Modelence method name (e.g., 'todo.create')
160
- - `defaultArgs` (object, optional): Default arguments merged with mutation variables
161
-
162
- **Returns:** Mutation configuration object with `mutationFn`
163
-
164
- ### `createQueryKey<T, U>(methodName, args?)`
165
-
166
- Utility function to create typed query keys for manual cache operations.
167
-
168
- **Parameters:**
169
- - `methodName` (T): The method name
170
- - `args` (U, optional): The arguments
171
-
172
- **Returns:** Typed query key array
173
-
174
- ## Migration from Modelence's useQuery/useMutation
175
-
176
- ### Before
177
-
178
- ```tsx
179
- import { useQuery, useMutation } from 'modelence/client';
180
-
181
- function TodoComponent() {
182
- const { data, isFetching, error } = useQuery('todo.getAll');
183
- const { mutate: createTodo } = useMutation('todo.create');
184
-
185
- // ...
186
- }
187
- ```
188
-
189
- ### After
190
-
191
- ```tsx
192
- import { useQuery, useMutation } from '@tanstack/react-query';
193
- import { getQueryOptions, getMutationOptions } from '@modelence/react-query';
194
-
195
- function TodoComponent() {
196
- const { data, isPending: isFetching, error } = useQuery(
197
- getQueryOptions('todo.getAll')
198
- );
199
- const { mutate: createTodo } = useMutation(
200
- getMutationOptions('todo.create')
201
- );
202
-
203
- // ...
204
- }
205
- ```
206
-
207
- ## Benefits
208
-
209
- 1. **Full TanStack Query API**: Access to all TanStack Query features and options
210
- 2. **Simple and Explicit**: Clear separation between Modelence configuration and TanStack Query options
211
- 3. **Better TypeScript Support**: Improved type inference and safety
212
- 4. **Familiar API**: Standard TanStack Query patterns that developers already know
213
- 5. **Future-Proof**: Easy to adopt new TanStack Query features as they're released
214
- 6. **Composability**: Easy to combine with other TanStack Query utilities
package/dist/index.d.ts CHANGED
@@ -2,11 +2,6 @@ type Args = Record<string, unknown>;
2
2
  /**
3
3
  * Creates query options for use with TanStack Query's useQuery hook.
4
4
  *
5
- * @typeParam T - The expected return type of the query
6
- * @param methodName - The name of the method to query
7
- * @param args - Optional arguments to pass to the method
8
- * @returns Query options object for TanStack Query's useQuery
9
- *
10
5
  * @example
11
6
  * ```tsx
12
7
  * import { useQuery } from '@tanstack/react-query';
@@ -26,6 +21,12 @@ type Args = Record<string, unknown>;
26
21
  * return <div>{data?.name}</div>;
27
22
  * }
28
23
  * ```
24
+ *
25
+ * @typeParam T - The expected return type of the query
26
+ * @param methodName - The name of the method to query
27
+ * @param args - Optional arguments to pass to the method
28
+ * @returns Query options object for TanStack Query's useQuery
29
+ *
29
30
  */
30
31
  declare function modelenceQuery<T = unknown>(methodName: string, args?: Args): {
31
32
  queryKey: (string | Args)[];
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["modelenceQuery","methodName","args","callMethod","modelenceMutation","defaultArgs","variables","createQueryKey"],"mappings":"0CAgCO,SAASA,CACdC,CAAAA,CAAAA,CACAC,CAAa,CAAA,EACb,CAAA,CACA,OAAO,CACL,QAAU,CAAA,CAACD,CAAYC,CAAAA,CAAI,CAC3B,CAAA,OAAA,CAAS,IAAMC,UAAAA,CAAcF,CAAYC,CAAAA,CAAI,CAC/C,CACF,CAiCO,SAASE,CACdH,CAAAA,CAAAA,CACAI,CAAoB,CAAA,EACpB,CAAA,CACA,OAAO,CACL,UAAY,CAAA,CAACC,CAAkB,CAAA,EAAOH,GAAAA,UAAAA,CAAcF,CAAY,CAAA,CAAE,GAAGI,CAAAA,CAAa,GAAGC,CAAU,CAAC,CAClG,CACF,CA8BO,SAASC,CAAAA,CACdN,CACAC,CAAAA,CAAAA,CAAU,EAAC,CACc,CACzB,OAAO,CAACD,CAAAA,CAAYC,CAAI,CAC1B","file":"index.js","sourcesContent":["import { callMethod } from 'modelence/client';\n\ntype Args = Record<string, unknown>;\n\n/**\n * Creates query options for use with TanStack Query's useQuery hook.\n * \n * @typeParam T - The expected return type of the query\n * @param methodName - The name of the method to query\n * @param args - Optional arguments to pass to the method\n * @returns Query options object for TanStack Query's useQuery\n * \n * @example\n * ```tsx\n * import { useQuery } from '@tanstack/react-query';\n * import { modelenceQuery } from '@modelence/react-query';\n * \n * function MyComponent() {\n * // Basic usage\n * const { data } = useQuery(modelenceQuery('todo.getAll'));\n * \n * // With additional options\n * const { data: todo } = useQuery({\n * ...modelenceQuery('todo.getById', { id: '123' }),\n * enabled: !!id,\n * staleTime: 5 * 60 * 1000,\n * });\n * \n * return <div>{data?.name}</div>;\n * }\n * ```\n */\nexport function modelenceQuery<T = unknown>(\n methodName: string, \n args: Args = {}\n) {\n return {\n queryKey: [methodName, args],\n queryFn: () => callMethod<T>(methodName, args),\n };\n}\n\n/**\n * Creates mutation options for use with TanStack Query's useMutation hook.\n * \n * @typeParam T - The expected return type of the mutation\n * @param methodName - The name of the method to mutate\n * @param defaultArgs - Optional default arguments to merge with mutation variables\n * @returns Mutation options object for TanStack Query's useMutation\n * \n * @example\n * ```tsx\n * import { useMutation, useQueryClient } from '@tanstack/react-query';\n * import { modelenceMutation } from '@modelence/react-query';\n * \n * function MyComponent() {\n * const queryClient = useQueryClient();\n * \n * // Basic usage\n * const { mutate } = useMutation(modelenceMutation('todos.create'));\n * \n * // With additional options\n * const { mutate: updateTodo } = useMutation({\n * ...modelenceMutation('todos.update'),\n * onSuccess: () => {\n * queryClient.invalidateQueries({ queryKey: ['todos.getAll'] });\n * },\n * });\n * \n * return <button onClick={() => mutate({ title: 'New Todo' })}>Create</button>;\n * }\n * ```\n */\nexport function modelenceMutation<T = unknown>(\n methodName: string, \n defaultArgs: Args = {}\n) {\n return {\n mutationFn: (variables: Args = {}) => callMethod<T>(methodName, { ...defaultArgs, ...variables }),\n };\n}\n\n/**\n * Type helper for creating properly typed query keys\n */\nexport type ModelenceQueryKey<T extends string, U extends Args = Args> = readonly [T, U];\n\n/**\n * Utility function to create query keys for manual cache operations\n * \n * @param methodName - The method name\n * @param args - The arguments\n * @returns Typed query key\n * \n * @example\n * ```tsx\n * import { useQueryClient } from '@tanstack/react-query';\n * import { createQueryKey } from '@modelence/react-query';\n * \n * function TodoActions() {\n * const queryClient = useQueryClient();\n * \n * const refreshTodos = () => {\n * queryClient.invalidateQueries({ \n * queryKey: createQueryKey('todo.getAll', { limit: 10 }) \n * });\n * };\n * }\n * ```\n */\nexport function createQueryKey<T extends string, U extends Args = Args>(\n methodName: T,\n args: U = {} as U\n): ModelenceQueryKey<T, U> {\n return [methodName, args] as const;\n}\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["modelenceQuery","methodName","args","callMethod","modelenceMutation","defaultArgs","variables","createQueryKey"],"mappings":"0CAiCO,SAASA,CACdC,CAAAA,CAAAA,CACAC,CAAa,CAAA,EACb,CAAA,CACA,OAAO,CACL,QAAU,CAAA,CAACD,CAAYC,CAAAA,CAAI,CAC3B,CAAA,OAAA,CAAS,IAAMC,UAAAA,CAAcF,CAAYC,CAAAA,CAAI,CAC/C,CACF,CAiCO,SAASE,CACdH,CAAAA,CAAAA,CACAI,CAAoB,CAAA,EACpB,CAAA,CACA,OAAO,CACL,UAAY,CAAA,CAACC,CAAkB,CAAA,EAAOH,GAAAA,UAAAA,CAAcF,CAAY,CAAA,CAAE,GAAGI,CAAAA,CAAa,GAAGC,CAAU,CAAC,CAClG,CACF,CA8BO,SAASC,CAAAA,CACdN,CACAC,CAAAA,CAAAA,CAAU,EAAC,CACc,CACzB,OAAO,CAACD,CAAAA,CAAYC,CAAI,CAC1B","file":"index.js","sourcesContent":["import { callMethod } from 'modelence/client';\n\ntype Args = Record<string, unknown>;\n\n/**\n * Creates query options for use with TanStack Query's useQuery hook.\n * \n * @example\n * ```tsx\n * import { useQuery } from '@tanstack/react-query';\n * import { modelenceQuery } from '@modelence/react-query';\n * \n * function MyComponent() {\n * // Basic usage\n * const { data } = useQuery(modelenceQuery('todo.getAll'));\n * \n * // With additional options\n * const { data: todo } = useQuery({\n * ...modelenceQuery('todo.getById', { id: '123' }),\n * enabled: !!id,\n * staleTime: 5 * 60 * 1000,\n * });\n * \n * return <div>{data?.name}</div>;\n * }\n * ```\n * \n * @typeParam T - The expected return type of the query\n * @param methodName - The name of the method to query\n * @param args - Optional arguments to pass to the method\n * @returns Query options object for TanStack Query's useQuery\n * \n */\nexport function modelenceQuery<T = unknown>(\n methodName: string, \n args: Args = {}\n) {\n return {\n queryKey: [methodName, args],\n queryFn: () => callMethod<T>(methodName, args),\n };\n}\n\n/**\n * Creates mutation options for use with TanStack Query's useMutation hook.\n * \n * @typeParam T - The expected return type of the mutation\n * @param methodName - The name of the method to mutate\n * @param defaultArgs - Optional default arguments to merge with mutation variables\n * @returns Mutation options object for TanStack Query's useMutation\n * \n * @example\n * ```tsx\n * import { useMutation, useQueryClient } from '@tanstack/react-query';\n * import { modelenceMutation } from '@modelence/react-query';\n * \n * function MyComponent() {\n * const queryClient = useQueryClient();\n * \n * // Basic usage\n * const { mutate } = useMutation(modelenceMutation('todos.create'));\n * \n * // With additional options\n * const { mutate: updateTodo } = useMutation({\n * ...modelenceMutation('todos.update'),\n * onSuccess: () => {\n * queryClient.invalidateQueries({ queryKey: ['todos.getAll'] });\n * },\n * });\n * \n * return <button onClick={() => mutate({ title: 'New Todo' })}>Create</button>;\n * }\n * ```\n */\nexport function modelenceMutation<T = unknown>(\n methodName: string, \n defaultArgs: Args = {}\n) {\n return {\n mutationFn: (variables: Args = {}) => callMethod<T>(methodName, { ...defaultArgs, ...variables }),\n };\n}\n\n/**\n * Type helper for creating properly typed query keys\n */\nexport type ModelenceQueryKey<T extends string, U extends Args = Args> = readonly [T, U];\n\n/**\n * Utility function to create query keys for manual cache operations\n * \n * @param methodName - The method name\n * @param args - The arguments\n * @returns Typed query key\n * \n * @example\n * ```tsx\n * import { useQueryClient } from '@tanstack/react-query';\n * import { createQueryKey } from '@modelence/react-query';\n * \n * function TodoActions() {\n * const queryClient = useQueryClient();\n * \n * const refreshTodos = () => {\n * queryClient.invalidateQueries({ \n * queryKey: createQueryKey('todo.getAll', { limit: 10 }) \n * });\n * };\n * }\n * ```\n */\nexport function createQueryKey<T extends string, U extends Args = Args>(\n methodName: T,\n args: U = {} as U\n): ModelenceQueryKey<T, U> {\n return [methodName, args] as const;\n}\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@modelence/react-query",
4
- "version": "1.0.0",
4
+ "version": "1.0.1",
5
5
  "description": "React Query utilities for Modelence",
6
6
  "exports": {
7
7
  ".": {
@@ -22,10 +22,8 @@
22
22
  "@tanstack/react-query": ">=5.0.0",
23
23
  "react": ">=18.0.0"
24
24
  },
25
- "dependencies": {
26
- "modelence": "^0.5.0"
27
- },
28
25
  "devDependencies": {
26
+ "modelence": "^0.5.0",
29
27
  "@tanstack/react-query": "^5.76.2",
30
28
  "@types/react": "^19.0.0",
31
29
  "react": "^19.0.0",
package/src/index.ts CHANGED
@@ -5,11 +5,6 @@ type Args = Record<string, unknown>;
5
5
  /**
6
6
  * Creates query options for use with TanStack Query's useQuery hook.
7
7
  *
8
- * @typeParam T - The expected return type of the query
9
- * @param methodName - The name of the method to query
10
- * @param args - Optional arguments to pass to the method
11
- * @returns Query options object for TanStack Query's useQuery
12
- *
13
8
  * @example
14
9
  * ```tsx
15
10
  * import { useQuery } from '@tanstack/react-query';
@@ -29,6 +24,12 @@ type Args = Record<string, unknown>;
29
24
  * return <div>{data?.name}</div>;
30
25
  * }
31
26
  * ```
27
+ *
28
+ * @typeParam T - The expected return type of the query
29
+ * @param methodName - The name of the method to query
30
+ * @param args - Optional arguments to pass to the method
31
+ * @returns Query options object for TanStack Query's useQuery
32
+ *
32
33
  */
33
34
  export function modelenceQuery<T = unknown>(
34
35
  methodName: string,
package/typedoc.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "$schema": "https://typedoc.org/schema.json",
3
+ "entryPoints": ["src/index.ts"],
4
+ "tsconfig": "./tsconfig.json",
5
+ "readme": "none",
6
+ "excludePrivate": true,
7
+ "excludeInternal": true,
8
+ "exclude": [
9
+ "**/node_modules/**",
10
+ "**/dist/**"
11
+ ]
12
+ }
@@ -1,249 +0,0 @@
1
- import React from 'react';
2
- import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
3
- import { getQueryOptions, getMutationOptions, createQueryKey } from '@modelence/react-query';
4
-
5
- interface Todo {
6
- id: string;
7
- title: string;
8
- completed: boolean;
9
- }
10
-
11
- // Example 1: Basic query usage
12
- function TodoList() {
13
- const { data: todos, isPending, error } = useQuery<Todo[]>(
14
- getQueryOptions('todo.getAll', { limit: 10 })
15
- );
16
-
17
- if (isPending) return <div>Loading todos...</div>;
18
- if (error) return <div>Error: {error.message}</div>;
19
-
20
- return (
21
- <div>
22
- <h2>Todos</h2>
23
- {todos?.map((todo) => (
24
- <div key={todo.id}>
25
- <h3>{todo.title}</h3>
26
- <p>{todo.completed ? '✅' : '⏳'}</p>
27
- </div>
28
- ))}
29
- </div>
30
- );
31
- }
32
-
33
- // Example 2: Query with options and enabled condition
34
- function TodoDetail({ todoId }: { todoId: string | null }) {
35
- const { data: todo, isPending } = useQuery<Todo>({
36
- ...getQueryOptions('todo.getById', { id: todoId }),
37
- enabled: !!todoId, // Only run when todoId exists
38
- staleTime: 5 * 60 * 1000, // 5 minutes
39
- retry: 3,
40
- });
41
-
42
- if (!todoId) return <div>Select a todo</div>;
43
- if (isPending) return <div>Loading todo...</div>;
44
-
45
- return (
46
- <div>
47
- <h3>{todo?.title}</h3>
48
- <p>Status: {todo?.completed ? 'Completed' : 'Pending'}</p>
49
- </div>
50
- );
51
- }
52
-
53
- // Example 3: Basic mutation
54
- function CreateTodo() {
55
- const queryClient = useQueryClient();
56
-
57
- const { mutate: createTodo, isPending, error } = useMutation<Todo, Error, { title: string; completed: boolean }>({
58
- ...getMutationOptions('todo.create'),
59
- onSuccess: () => {
60
- // Invalidate and refetch all todo queries
61
- queryClient.invalidateQueries({ queryKey: ['todo.getAll'] });
62
- },
63
- onError: (error) => {
64
- console.error('Failed to create todo:', error);
65
- },
66
- });
67
-
68
- const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
69
- e.preventDefault();
70
- const formData = new FormData(e.currentTarget);
71
- const title = formData.get('title') as string;
72
-
73
- createTodo({ title, completed: false });
74
- e.currentTarget.reset();
75
- };
76
-
77
- return (
78
- <form onSubmit={handleSubmit}>
79
- <input
80
- name="title"
81
- placeholder="Enter todo title"
82
- required
83
- disabled={isPending}
84
- />
85
- <button type="submit" disabled={isPending}>
86
- {isPending ? 'Creating...' : 'Create Todo'}
87
- </button>
88
- {error && <p style={{ color: 'red' }}>Error: {error.message}</p>}
89
- </form>
90
- );
91
- }
92
-
93
- // Example 4: Mutation with default args
94
- function UpdateTodo({ todoId }: { todoId: string }) {
95
- const queryClient = useQueryClient();
96
-
97
- const { mutate: updateTodo, isPending } = useMutation<Todo, Error, { completed: boolean }>({
98
- ...getMutationOptions('todo.update', { id: todoId }), // Default id
99
- onSuccess: () => {
100
- // Invalidate specific todo and list
101
- queryClient.invalidateQueries({ queryKey: ['todo.getById'] });
102
- queryClient.invalidateQueries({ queryKey: ['todo.getAll'] });
103
- },
104
- });
105
-
106
- const toggleComplete = () => {
107
- // The id is already provided in defaultArgs, so we only need the fields to update
108
- updateTodo({ completed: true });
109
- };
110
-
111
- return (
112
- <button onClick={toggleComplete} disabled={isPending}>
113
- {isPending ? 'Updating...' : 'Mark Complete'}
114
- </button>
115
- );
116
- }
117
-
118
- // Example 5: Manual cache operations
119
- function TodoActions() {
120
- const queryClient = useQueryClient();
121
-
122
- const refreshTodos = () => {
123
- queryClient.invalidateQueries({
124
- queryKey: createQueryKey('todo.getAll', { limit: 10 })
125
- });
126
- };
127
-
128
- const prefetchTodo = (id: string) => {
129
- queryClient.prefetchQuery<Todo>({
130
- ...getQueryOptions('todo.getById', { id }),
131
- staleTime: 10 * 60 * 1000, // 10 minutes
132
- });
133
- };
134
-
135
- const setTodoData = (id: string, todo: Todo) => {
136
- queryClient.setQueryData(
137
- createQueryKey('todo.getById', { id }),
138
- todo
139
- );
140
- };
141
-
142
- return (
143
- <div>
144
- <button onClick={refreshTodos}>Refresh Todos</button>
145
- <button onClick={() => prefetchTodo('123')}>Prefetch Todo 123</button>
146
- <button onClick={() => setTodoData('123', { id: '123', title: 'Test', completed: false })}>
147
- Set Todo Data
148
- </button>
149
- </div>
150
- );
151
- }
152
-
153
- // Example 6: Advanced usage with optimistic updates
154
- function OptimisticTodo({ todoId }: { todoId: string }) {
155
- const queryClient = useQueryClient();
156
-
157
- const { mutate: updateTodo } = useMutation<
158
- Todo,
159
- Error,
160
- { id: string; completed: boolean },
161
- { previousTodo: Todo | undefined }
162
- >({
163
- ...getMutationOptions('todo.update'),
164
- onMutate: async (variables) => {
165
- // Cancel outgoing refetches (so they don't overwrite our optimistic update)
166
- await queryClient.cancelQueries({
167
- queryKey: createQueryKey('todo.getById', { id: todoId })
168
- });
169
-
170
- // Snapshot the previous value
171
- const previousTodo = queryClient.getQueryData<Todo>(
172
- createQueryKey('todo.getById', { id: todoId })
173
- );
174
-
175
- // Optimistically update to the new value
176
- queryClient.setQueryData(
177
- createQueryKey('todo.getById', { id: todoId }),
178
- (old: Todo | undefined) => old ? { ...old, ...variables } : undefined
179
- );
180
-
181
- // Return a context object with the snapshotted value
182
- return { previousTodo };
183
- },
184
- onError: (_err, _variables, context) => {
185
- // If the mutation fails, use the context to roll back
186
- if (context?.previousTodo) {
187
- queryClient.setQueryData(
188
- createQueryKey('todo.getById', { id: todoId }),
189
- context.previousTodo
190
- );
191
- }
192
- },
193
- onSettled: () => {
194
- // Always refetch after error or success
195
- queryClient.invalidateQueries({
196
- queryKey: createQueryKey('todo.getById', { id: todoId })
197
- });
198
- },
199
- });
200
-
201
- return (
202
- <button onClick={() => updateTodo({ id: todoId, completed: true })}>
203
- Update with Optimistic UI
204
- </button>
205
- );
206
- }
207
-
208
- // Main app component showcasing all examples
209
- export default function App() {
210
- const [selectedTodoId, setSelectedTodoId] = React.useState<string | null>(null);
211
-
212
- return (
213
- <div style={{ padding: '20px', maxWidth: '800px', margin: '0 auto' }}>
214
- <h1>@modelence/react-query Examples</h1>
215
-
216
- <section>
217
- <h2>Create Todo</h2>
218
- <CreateTodo />
219
- </section>
220
-
221
- <section>
222
- <h2>Todo List</h2>
223
- <TodoList />
224
- </section>
225
-
226
- <section>
227
- <h2>Todo Detail</h2>
228
- <input
229
- placeholder="Enter todo ID"
230
- onChange={(e) => setSelectedTodoId(e.target.value || null)}
231
- />
232
- <TodoDetail todoId={selectedTodoId} />
233
- </section>
234
-
235
- {selectedTodoId && (
236
- <section>
237
- <h2>Todo Actions</h2>
238
- <UpdateTodo todoId={selectedTodoId} />
239
- <OptimisticTodo todoId={selectedTodoId} />
240
- </section>
241
- )}
242
-
243
- <section>
244
- <h2>Cache Actions</h2>
245
- <TodoActions />
246
- </section>
247
- </div>
248
- );
249
- }