@osdk/react 0.9.0-beta.6 → 0.9.0-beta.8
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/AGENTS.md +253 -0
- package/CHANGELOG.md +31 -0
- package/build/browser/intellisense.test.js +1 -1
- package/build/browser/intellisense.test.js.map +1 -1
- package/build/browser/new/useLinks.js.map +1 -1
- package/build/browser/new/useOsdkAggregation.js.map +1 -1
- package/build/browser/new/useOsdkFunction.js +101 -0
- package/build/browser/new/useOsdkFunction.js.map +1 -0
- package/build/browser/new/useOsdkObjects.js.map +1 -1
- package/build/browser/public/experimental.js +1 -0
- package/build/browser/public/experimental.js.map +1 -1
- package/build/cjs/public/experimental.cjs +50 -2
- package/build/cjs/public/experimental.cjs.map +1 -1
- package/build/cjs/public/experimental.d.cts +132 -21
- package/build/esm/intellisense.test.js +1 -1
- package/build/esm/intellisense.test.js.map +1 -1
- package/build/esm/new/useLinks.js.map +1 -1
- package/build/esm/new/useOsdkAggregation.js.map +1 -1
- package/build/esm/new/useOsdkFunction.js +101 -0
- package/build/esm/new/useOsdkFunction.js.map +1 -0
- package/build/esm/new/useOsdkObjects.js.map +1 -1
- package/build/esm/public/experimental.js +1 -0
- package/build/esm/public/experimental.js.map +1 -1
- package/build/types/new/useLinks.d.ts +5 -5
- package/build/types/new/useLinks.d.ts.map +1 -1
- package/build/types/new/useOsdkAggregation.d.ts +5 -6
- package/build/types/new/useOsdkAggregation.d.ts.map +1 -1
- package/build/types/new/useOsdkFunction.d.ts +112 -0
- package/build/types/new/useOsdkFunction.d.ts.map +1 -0
- package/build/types/new/useOsdkObjects.d.ts +5 -5
- package/build/types/new/useOsdkObjects.d.ts.map +1 -1
- package/build/types/public/experimental.d.ts +2 -0
- package/build/types/public/experimental.d.ts.map +1 -1
- package/docs/actions.md +414 -0
- package/docs/advanced-queries.md +663 -0
- package/docs/cache-management.md +213 -0
- package/docs/getting-started.md +382 -0
- package/docs/platform-apis.md +203 -0
- package/docs/querying-data.md +648 -0
- package/package.json +10 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"experimental.js","names":["OsdkProvider2","useCurrentFoundryUser","useFoundryUser","useFoundryUsersList","useLinks","useObjectSet","useOsdkAction","useOsdkAggregation","useOsdkObject","useOsdkObjects","useOsdkClient","useOsdkMetadata","useDebouncedCallback"],"sources":["experimental.ts"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport { OsdkProvider2 } from \"../new/OsdkProvider2.js\";\nexport { useCurrentFoundryUser } from \"../new/platform-apis/admin/useCurrentFoundryUser.js\";\nexport { useFoundryUser } from \"../new/platform-apis/admin/useFoundryUser.js\";\nexport { useFoundryUsersList } from \"../new/platform-apis/admin/useFoundryUsersList.js\";\nexport { useLinks } from \"../new/useLinks.js\";\nexport { useObjectSet } from \"../new/useObjectSet.js\";\nexport { useOsdkAction } from \"../new/useOsdkAction.js\";\nexport type { UseOsdkAggregationResult } from \"../new/useOsdkAggregation.js\";\nexport { useOsdkAggregation } from \"../new/useOsdkAggregation.js\";\nexport { useOsdkObject } from \"../new/useOsdkObject.js\";\nexport type { UseOsdkListResult } from \"../new/useOsdkObjects.js\";\nexport { useOsdkObjects } from \"../new/useOsdkObjects.js\";\nexport { useOsdkClient } from \"../useOsdkClient.js\";\nexport { useOsdkMetadata } from \"../useOsdkMetadata.js\";\nexport type { UseOsdkMetadataResult } from \"../useOsdkMetadata.js\";\nexport { useDebouncedCallback } from \"../utils/useDebouncedCallback.js\";\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,SAASA,aAAa,QAAQ,yBAAyB;AACvD,SAASC,qBAAqB,QAAQ,qDAAqD;AAC3F,SAASC,cAAc,QAAQ,8CAA8C;AAC7E,SAASC,mBAAmB,QAAQ,mDAAmD;AACvF,SAASC,QAAQ,QAAQ,oBAAoB;AAC7C,SAASC,YAAY,QAAQ,wBAAwB;AACrD,SAASC,aAAa,QAAQ,yBAAyB;AAEvD,SAASC,kBAAkB,QAAQ,8BAA8B;
|
|
1
|
+
{"version":3,"file":"experimental.js","names":["OsdkProvider2","useCurrentFoundryUser","useFoundryUser","useFoundryUsersList","useLinks","useObjectSet","useOsdkAction","useOsdkAggregation","useOsdkFunction","useOsdkObject","useOsdkObjects","useOsdkClient","useOsdkMetadata","useDebouncedCallback"],"sources":["experimental.ts"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport { OsdkProvider2 } from \"../new/OsdkProvider2.js\";\nexport { useCurrentFoundryUser } from \"../new/platform-apis/admin/useCurrentFoundryUser.js\";\nexport { useFoundryUser } from \"../new/platform-apis/admin/useFoundryUser.js\";\nexport { useFoundryUsersList } from \"../new/platform-apis/admin/useFoundryUsersList.js\";\nexport { useLinks } from \"../new/useLinks.js\";\nexport { useObjectSet } from \"../new/useObjectSet.js\";\nexport { useOsdkAction } from \"../new/useOsdkAction.js\";\nexport type { UseOsdkAggregationResult } from \"../new/useOsdkAggregation.js\";\nexport { useOsdkAggregation } from \"../new/useOsdkAggregation.js\";\nexport type {\n UseOsdkFunctionOptions,\n UseOsdkFunctionResult,\n} from \"../new/useOsdkFunction.js\";\nexport { useOsdkFunction } from \"../new/useOsdkFunction.js\";\nexport { useOsdkObject } from \"../new/useOsdkObject.js\";\nexport type { UseOsdkListResult } from \"../new/useOsdkObjects.js\";\nexport { useOsdkObjects } from \"../new/useOsdkObjects.js\";\nexport { useOsdkClient } from \"../useOsdkClient.js\";\nexport { useOsdkMetadata } from \"../useOsdkMetadata.js\";\nexport type { UseOsdkMetadataResult } from \"../useOsdkMetadata.js\";\nexport { useDebouncedCallback } from \"../utils/useDebouncedCallback.js\";\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,SAASA,aAAa,QAAQ,yBAAyB;AACvD,SAASC,qBAAqB,QAAQ,qDAAqD;AAC3F,SAASC,cAAc,QAAQ,8CAA8C;AAC7E,SAASC,mBAAmB,QAAQ,mDAAmD;AACvF,SAASC,QAAQ,QAAQ,oBAAoB;AAC7C,SAASC,YAAY,QAAQ,wBAAwB;AACrD,SAASC,aAAa,QAAQ,yBAAyB;AAEvD,SAASC,kBAAkB,QAAQ,8BAA8B;AAKjE,SAASC,eAAe,QAAQ,2BAA2B;AAC3D,SAASC,aAAa,QAAQ,yBAAyB;AAEvD,SAASC,cAAc,QAAQ,0BAA0B;AACzD,SAASC,aAAa,QAAQ,qBAAqB;AACnD,SAASC,eAAe,QAAQ,uBAAuB;AAEvD,SAASC,oBAAoB,QAAQ,kCAAkC","ignoreList":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { LinkedType, LinkNames } from "@osdk/api";
|
|
2
|
-
import type {
|
|
3
|
-
export interface UseLinksOptions<T extends
|
|
1
|
+
import type { LinkedType, LinkNames, ObjectOrInterfaceDefinition } from "@osdk/api";
|
|
2
|
+
import type { Osdk, PropertyKeys, WhereClause } from "@osdk/client";
|
|
3
|
+
export interface UseLinksOptions<T extends ObjectOrInterfaceDefinition> {
|
|
4
4
|
/**
|
|
5
5
|
* Standard OSDK Where clause for filtering linked objects
|
|
6
6
|
*/
|
|
@@ -39,7 +39,7 @@ export interface UseLinksOptions<T extends ObjectTypeDefinition | InterfaceDefin
|
|
|
39
39
|
*/
|
|
40
40
|
enabled?: boolean;
|
|
41
41
|
}
|
|
42
|
-
export interface UseLinksResult<Q extends
|
|
42
|
+
export interface UseLinksResult<Q extends ObjectOrInterfaceDefinition> {
|
|
43
43
|
links: Osdk.Instance<Q>[] | undefined;
|
|
44
44
|
isLoading: boolean;
|
|
45
45
|
error: Error | undefined;
|
|
@@ -65,6 +65,6 @@ export interface UseLinksResult<Q extends ObjectTypeDefinition | InterfaceDefini
|
|
|
65
65
|
* @returns UseLinksResult with links data and metadata
|
|
66
66
|
*/
|
|
67
67
|
export declare function useLinks<
|
|
68
|
-
T extends
|
|
68
|
+
T extends ObjectOrInterfaceDefinition,
|
|
69
69
|
L extends LinkNames<T>
|
|
70
70
|
>(objects: Osdk.Instance<T> | Array<Osdk.Instance<T>> | undefined, linkName: L, options?: UseLinksOptions<LinkedType<T, L>>): UseLinksResult<LinkedType<T, L>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"AAgBA,
|
|
1
|
+
{"mappings":"AAgBA,cACE,YACA,WACA,mCACK,WAAY;AACnB,cAAc,MAAM,cAAc,mBAAmB,cAAe;AAMpE,iBAAiB,gBACf,UAAU,6BACV;;;;CAIA,QAAQ,YAAY;;;;CAKpB;;CAGA,aACG,KAAK,aAAa,OAAM,QAAQ;;;;;;;CASnC,OAAO,UAAU;;;;;;;;;;;;;;;;;;;;CAqBjB;AACD;AAED,iBAAiB,eACf,UAAU,6BACV;CACA,OAAO,KAAK,SAAS;CACrB;CACA,OAAO;;;;CAKP;;;;CAKA,kBAAkB;;;;CAKlB;AACD;;;;;;;;;AAYD,OAAO,iBAAS;CACd,UAAU;CACV,UAAU,UAAU;EAEpBA,SAAS,KAAK,SAAS,KAAK,MAAM,KAAK,SAAS,iBAChDC,UAAU,GACVC,UAAS,gBAAgB,WAAW,GAAG,MACtC,eAAe,WAAW,GAAG","names":["objects: Osdk.Instance<T> | Array<Osdk.Instance<T>> | undefined","linkName: L","options: UseLinksOptions<LinkedType<T, L>>"],"sources":["../../../src/new/useLinks.ts"],"version":3,"file":"useLinks.d.ts"}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import type { AggregateOpts, AggregationsResults, DerivedProperty, WhereClause } from "@osdk/api";
|
|
2
|
-
import type { ObjectTypeDefinition } from "@osdk/client";
|
|
1
|
+
import type { AggregateOpts, AggregationsResults, DerivedProperty, ObjectOrInterfaceDefinition, WhereClause } from "@osdk/api";
|
|
3
2
|
import type { InferRdpTypes } from "./types.js";
|
|
4
3
|
export interface UseOsdkAggregationOptions<
|
|
5
|
-
T extends
|
|
4
|
+
T extends ObjectOrInterfaceDefinition,
|
|
6
5
|
A extends AggregateOpts<T>,
|
|
7
6
|
WithProps extends DerivedProperty.Clause<T> | undefined = undefined
|
|
8
7
|
> {
|
|
@@ -28,7 +27,7 @@ export interface UseOsdkAggregationOptions<
|
|
|
28
27
|
dedupeIntervalMs?: number;
|
|
29
28
|
}
|
|
30
29
|
export interface UseOsdkAggregationResult<
|
|
31
|
-
T extends
|
|
30
|
+
T extends ObjectOrInterfaceDefinition,
|
|
32
31
|
A extends AggregateOpts<T>
|
|
33
32
|
> {
|
|
34
33
|
data: AggregationsResults<T, A> | undefined;
|
|
@@ -61,7 +60,7 @@ export interface UseOsdkAggregationResult<
|
|
|
61
60
|
* ```
|
|
62
61
|
*/
|
|
63
62
|
export declare function useOsdkAggregation<
|
|
64
|
-
Q extends
|
|
65
|
-
A extends AggregateOpts<Q>,
|
|
63
|
+
Q extends ObjectOrInterfaceDefinition,
|
|
64
|
+
const A extends AggregateOpts<Q>,
|
|
66
65
|
WP extends DerivedProperty.Clause<Q> | undefined = undefined
|
|
67
66
|
>(type: Q, { where, withProperties, aggregate, dedupeIntervalMs }: UseOsdkAggregationOptions<Q, A, WP>): UseOsdkAggregationResult<Q, A>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"AAgBA,cACE,eACA,qBACA,iBACA,mBACK,WAAY;
|
|
1
|
+
{"mappings":"AAgBA,cACE,eACA,qBACA,iBACA,6BACA,mBACK,WAAY;AAKnB,cAAc,qBAAqB,YAAa;AAEhD,iBAAiB;CACf,UAAU;CACV,UAAU,cAAc;CACxB,kBAAkB,gBAAgB,OAAO;EACzC;;;;CAIA,QAAQ,YAAY,GAAG,cAAc,GAAG;;;;;CAMxC,iBAAiB;;;;CAKjB,WAAW;;;;;;;CAQX;AACD;AAED,iBAAiB;CACf,UAAU;CACV,UAAU,cAAc;EACxB;CACA,MAAM,oBAAoB,GAAG;CAC7B;CACA,OAAO;CACP;AACD;;;;;;;;;;;;;;;;;;;;;;;;;AAgCD,OAAO,iBAAS;CACd,UAAU;OACJ,UAAU,cAAc;CAC9B,WAAW,gBAAgB,OAAO;EAElCA,MAAM,GACN,EACE,OACA,gBACA,WACA,kBACoC,EAAnC,0BAA0B,GAAG,GAAG,MAClC,yBAAyB,GAAG","names":["type: Q"],"sources":["../../../src/new/useOsdkAggregation.ts"],"version":3,"file":"useOsdkAggregation.d.ts"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import type { CompileTimeMetadata, ObjectTypeDefinition, Osdk, QueryDefinition } from "@osdk/api";
|
|
2
|
+
import type { QueryParameterType, QueryReturnType } from "@osdk/client/unstable-do-not-use";
|
|
3
|
+
export interface UseOsdkFunctionOptions<Q extends QueryDefinition<unknown>> {
|
|
4
|
+
/**
|
|
5
|
+
* Parameters to pass to the function.
|
|
6
|
+
* Must include all required parameters; optional parameters can be omitted.
|
|
7
|
+
*/
|
|
8
|
+
params?: CompileTimeMetadata<Q>["parameters"] extends Record<string, never> ? undefined : QueryParameterType<CompileTimeMetadata<Q>["parameters"]>;
|
|
9
|
+
/**
|
|
10
|
+
* Object types this function depends on.
|
|
11
|
+
* When actions modify objects of these types, the function will automatically refetch.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```tsx
|
|
15
|
+
* // Refetch when any Employee object changes
|
|
16
|
+
* { dependsOn: [Employee] }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
dependsOn?: Array<ObjectTypeDefinition | string>;
|
|
20
|
+
/**
|
|
21
|
+
* Specific object instances this function depends on.
|
|
22
|
+
* When any of these specific objects change, the function will refetch.
|
|
23
|
+
* More fine-grained than dependsOn for precise invalidation control.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```tsx
|
|
27
|
+
* // Refetch when this specific employee changes
|
|
28
|
+
* { dependsOnObjects: [employee] }
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
dependsOnObjects?: Array<Osdk.Instance<ObjectTypeDefinition>>;
|
|
32
|
+
/**
|
|
33
|
+
* The number of milliseconds to dedupe identical function calls.
|
|
34
|
+
* Two calls with the same function and params will share results
|
|
35
|
+
* if the second call is within this interval of the first.
|
|
36
|
+
* @default 2000
|
|
37
|
+
*/
|
|
38
|
+
dedupeIntervalMs?: number;
|
|
39
|
+
/**
|
|
40
|
+
* Whether to enable the query. When false, the query will not execute.
|
|
41
|
+
* Useful for:
|
|
42
|
+
* - Dependent queries that need to wait for other data
|
|
43
|
+
* - Conditional queries based on component state
|
|
44
|
+
*
|
|
45
|
+
* @default true
|
|
46
|
+
* @example
|
|
47
|
+
* // Dependent query - wait for required data
|
|
48
|
+
* const { data: employee } = useOsdkObject(Employee, employeeId);
|
|
49
|
+
* const { data: report } = useOsdkFunction(getEmployeeReport, {
|
|
50
|
+
* params: { employeeId: employee?.$primaryKey },
|
|
51
|
+
* enabled: !!employee
|
|
52
|
+
* });
|
|
53
|
+
*/
|
|
54
|
+
enabled?: boolean;
|
|
55
|
+
}
|
|
56
|
+
export interface UseOsdkFunctionResult<Q extends QueryDefinition<unknown>> {
|
|
57
|
+
/**
|
|
58
|
+
* The function result, or undefined if not yet loaded or on error.
|
|
59
|
+
*/
|
|
60
|
+
data: QueryReturnType<CompileTimeMetadata<Q>["output"]> | undefined;
|
|
61
|
+
/**
|
|
62
|
+
* True while the function is executing.
|
|
63
|
+
*/
|
|
64
|
+
isLoading: boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Error if the function execution failed.
|
|
67
|
+
*/
|
|
68
|
+
error: Error | undefined;
|
|
69
|
+
/**
|
|
70
|
+
* Timestamp (ms since epoch) of when the result was last fetched.
|
|
71
|
+
*/
|
|
72
|
+
lastUpdated: number;
|
|
73
|
+
/**
|
|
74
|
+
* Manually refetch the function.
|
|
75
|
+
* Useful for "pull to refresh" or retry patterns.
|
|
76
|
+
*/
|
|
77
|
+
refetch: () => void;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* React hook for executing and observing OSDK functions.
|
|
81
|
+
*
|
|
82
|
+
* Provides automatic caching, deduplication, and reactive updates for function calls.
|
|
83
|
+
* Functions are automatically re-fetched when dependencies change (configured via options).
|
|
84
|
+
*
|
|
85
|
+
* @param queryDef - The QueryDefinition to execute
|
|
86
|
+
* @param options - Configuration options for the function call
|
|
87
|
+
* @returns Object containing result, loading state, error, and refetch function
|
|
88
|
+
*
|
|
89
|
+
* @example Basic usage
|
|
90
|
+
* ```tsx
|
|
91
|
+
* const { data, isLoading, error } = useOsdkFunction(getEmployeeStats, {
|
|
92
|
+
* params: { departmentId: "engineering" }
|
|
93
|
+
* });
|
|
94
|
+
* ```
|
|
95
|
+
*
|
|
96
|
+
* @example With dependency tracking
|
|
97
|
+
* ```tsx
|
|
98
|
+
* const { data, refetch } = useOsdkFunction(calculateMetrics, {
|
|
99
|
+
* params: { startDate, endDate },
|
|
100
|
+
* dependsOn: [Employee, Project],
|
|
101
|
+
* });
|
|
102
|
+
* ```
|
|
103
|
+
*
|
|
104
|
+
* @example With specific object dependencies
|
|
105
|
+
* ```tsx
|
|
106
|
+
* const { data } = useOsdkFunction(getEmployeeReport, {
|
|
107
|
+
* params: { employeeId: employee.$primaryKey },
|
|
108
|
+
* dependsOnObjects: [employee],
|
|
109
|
+
* });
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
export declare function useOsdkFunction<Q extends QueryDefinition<unknown>>(queryDef: Q, options?: UseOsdkFunctionOptions<Q>): UseOsdkFunctionResult<Q>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"mappings":"AAgBA,cACE,qBACA,sBACA,MACA,uBACK,WAAY;AACnB,cAEE,oBACA,uBACK,kCAAmC;AAK1C,iBAAiB,uBAAuB,UAAU,0BAA0B;;;;;CAK1E,SAAS,oBAAoB,GAAG,sBAAsB,oCAElD,mBAAmB,oBAAoB,GAAG;;;;;;;;;;;CAY9C,YAAY,MAAM;;;;;;;;;;;;CAalB,mBAAmB,MAAM,KAAK,SAAS;;;;;;;CAQvC;;;;;;;;;;;;;;;;CAiBA;AACD;AAED,iBAAiB,sBAAsB,UAAU,0BAA0B;;;;CAIzE,MAAM,gBAAgB,oBAAoB,GAAG;;;;CAK7C;;;;CAKA,OAAO;;;;CAKP;;;;;CAMA;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCD,OAAO,iBAAS,gBAAgB,UAAU,0BACxCA,UAAU,GACVC,UAAS,uBAAuB,KAC/B,sBAAsB","names":["queryDef: Q","options: UseOsdkFunctionOptions<Q>"],"sources":["../../../src/new/useOsdkFunction.ts"],"version":3,"file":"useOsdkFunction.d.ts"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { DerivedProperty,
|
|
1
|
+
import type { DerivedProperty, LinkedType, LinkNames, ObjectOrInterfaceDefinition, Osdk, PropertyKeys, SimplePropertyDef, WhereClause } from "@osdk/api";
|
|
2
2
|
import type { InferRdpTypes } from "./types.js";
|
|
3
3
|
export interface UseOsdkObjectsOptions<
|
|
4
|
-
T extends
|
|
4
|
+
T extends ObjectOrInterfaceDefinition,
|
|
5
5
|
WithProps extends DerivedProperty.Clause<T> | undefined = undefined
|
|
6
6
|
> {
|
|
7
7
|
/**
|
|
@@ -107,7 +107,7 @@ export interface UseOsdkObjectsOptions<
|
|
|
107
107
|
enabled?: boolean;
|
|
108
108
|
}
|
|
109
109
|
export interface UseOsdkListResult<
|
|
110
|
-
T extends
|
|
110
|
+
T extends ObjectOrInterfaceDefinition,
|
|
111
111
|
RDPs extends Record<string, SimplePropertyDef> = {}
|
|
112
112
|
> {
|
|
113
113
|
fetchMore: (() => Promise<void>) | undefined;
|
|
@@ -124,12 +124,12 @@ export interface UseOsdkListResult<
|
|
|
124
124
|
isOptimistic: boolean;
|
|
125
125
|
}
|
|
126
126
|
export declare function useOsdkObjects<
|
|
127
|
-
Q extends
|
|
127
|
+
Q extends ObjectOrInterfaceDefinition,
|
|
128
128
|
L extends LinkNames<Q>
|
|
129
129
|
>(type: Q, options: UseOsdkObjectsOptions<Q> & {
|
|
130
130
|
pivotTo: L
|
|
131
131
|
}): UseOsdkListResult<LinkedType<Q, L>>;
|
|
132
132
|
export declare function useOsdkObjects<
|
|
133
|
-
Q extends
|
|
133
|
+
Q extends ObjectOrInterfaceDefinition,
|
|
134
134
|
WP extends DerivedProperty.Clause<Q> | undefined
|
|
135
135
|
>(type: Q, options?: UseOsdkObjectsOptions<Q, WP>): UseOsdkListResult<Q, InferRdpTypes<Q, WP>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"AAgBA,cACE,iBACA,
|
|
1
|
+
{"mappings":"AAgBA,cACE,iBACA,YACA,WACA,6BACA,MACA,cACA,mBACA,mBACK,WAAY;AAKnB,cAAc,qBAAqB,YAAa;AAEhD,iBAAiB;CACf,UAAU;CACV,kBAAkB,gBAAgB,OAAO;EACzC;;;;CAIA,QAAQ,YAAY,GAAG,cAAc,GAAG;;;;CAKxC;;CAGA,aACG,KAAK,aAAa,OAAM,QAAQ;;;;;CAOnC,iBAAiB;;;;;;CAOjB,gBAAgB,MAAM;EACpB,OAAO,YAAY,GAAG,cAAc,GAAG;CACxC;;;;;CAMD,UAAU,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;CA0BpB;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BA;CAEA;;;;;;;;;;;;;;;;;;;;;CAsBA;AACD;AAED,iBAAiB;CACf,UAAU;CACV,aAAa,eAAe,qBAAqB,CAAE;EACnD;CACA,kBAAkB;CAClB,MACI,KAAK,SAAS,GAAG,sBAAsB,aAAa,IAAI;CAE5D;CAEA,OAAO;;;;;;;;CASP;AACD;AAQD,OAAO,iBAAS;CACd,UAAU;CACV,UAAU,UAAU;EAEpBA,MAAM,GACNC,SAAS,sBAAsB,KAAK;CAAE,SAAS;AAAG,IACjD,kBAAkB,WAAW,GAAG;AAEnC,OAAO,iBAAS;CACd,UAAU;CACV,WAAW,gBAAgB,OAAO;EAElCD,MAAM,GACNE,UAAU,sBAAsB,GAAG,MAClC,kBAAkB,GAAG,cAAc,GAAG","names":["type: Q","options: UseOsdkObjectsOptions<Q> & { pivotTo: L }","options?: UseOsdkObjectsOptions<Q, WP>"],"sources":["../../../src/new/useOsdkObjects.ts"],"version":3,"file":"useOsdkObjects.d.ts"}
|
|
@@ -7,6 +7,8 @@ export { useObjectSet } from "../new/useObjectSet.js";
|
|
|
7
7
|
export { useOsdkAction } from "../new/useOsdkAction.js";
|
|
8
8
|
export type { UseOsdkAggregationResult } from "../new/useOsdkAggregation.js";
|
|
9
9
|
export { useOsdkAggregation } from "../new/useOsdkAggregation.js";
|
|
10
|
+
export type { UseOsdkFunctionOptions, UseOsdkFunctionResult } from "../new/useOsdkFunction.js";
|
|
11
|
+
export { useOsdkFunction } from "../new/useOsdkFunction.js";
|
|
10
12
|
export { useOsdkObject } from "../new/useOsdkObject.js";
|
|
11
13
|
export type { UseOsdkListResult } from "../new/useOsdkObjects.js";
|
|
12
14
|
export { useOsdkObjects } from "../new/useOsdkObjects.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"AAgBA,SAAS,qBAAqB;AAC9B,SAAS,6BAA6B;AACtC,SAAS,sBAAsB;AAC/B,SAAS,2BAA2B;AACpC,SAAS,gBAAgB;AACzB,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAC9B,cAAc,gCAAgC;AAC9C,SAAS,0BAA0B;AACnC,SAAS,qBAAqB;AAC9B,cAAc,yBAAyB;AACvC,SAAS,sBAAsB;AAC/B,SAAS,qBAAqB;AAC9B,SAAS,uBAAuB;AAChC,cAAc,6BAA6B;AAC3C,SAAS,4BAA4B","names":[],"sources":["../../../src/public/experimental.ts"],"version":3,"file":"experimental.d.ts"}
|
|
1
|
+
{"mappings":"AAgBA,SAAS,qBAAqB;AAC9B,SAAS,6BAA6B;AACtC,SAAS,sBAAsB;AAC/B,SAAS,2BAA2B;AACpC,SAAS,gBAAgB;AACzB,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAC9B,cAAc,gCAAgC;AAC9C,SAAS,0BAA0B;AACnC,cACE,wBACA,6BACK;AACP,SAAS,uBAAuB;AAChC,SAAS,qBAAqB;AAC9B,cAAc,yBAAyB;AACvC,SAAS,sBAAsB;AAC/B,SAAS,qBAAqB;AAC9B,SAAS,uBAAuB;AAChC,cAAc,6BAA6B;AAC3C,SAAS,4BAA4B","names":[],"sources":["../../../src/public/experimental.ts"],"version":3,"file":"experimental.d.ts"}
|
package/docs/actions.md
ADDED
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
---
|
|
2
|
+
sidebar_position: 3
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Actions
|
|
6
|
+
|
|
7
|
+
This guide covers executing actions, validation, optimistic updates, and debouncing patterns.
|
|
8
|
+
|
|
9
|
+
## useOsdkAction
|
|
10
|
+
|
|
11
|
+
*Experimental - import from `@osdk/react/experimental`*
|
|
12
|
+
|
|
13
|
+
Execute and validate actions with automatic state management.
|
|
14
|
+
|
|
15
|
+
### Basic Usage
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { $Actions, Todo } from "@my/osdk";
|
|
19
|
+
import { useOsdkAction, useOsdkObject } from "@osdk/react/experimental";
|
|
20
|
+
import { useCallback } from "react";
|
|
21
|
+
|
|
22
|
+
function TodoView({ todo }: { todo: Todo.OsdkInstance }) {
|
|
23
|
+
const { isLoading } = useOsdkObject(todo);
|
|
24
|
+
const { applyAction, data, error, isPending } = useOsdkAction(
|
|
25
|
+
$Actions.completeTodo,
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const onClick = useCallback(() => {
|
|
29
|
+
applyAction({
|
|
30
|
+
todo: todo,
|
|
31
|
+
isComplete: true,
|
|
32
|
+
});
|
|
33
|
+
}, [applyAction, todo]);
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<div>
|
|
37
|
+
<div>
|
|
38
|
+
{todo.title}
|
|
39
|
+
{todo.isComplete === false && (
|
|
40
|
+
<button onClick={onClick} disabled={isPending}>
|
|
41
|
+
Mark Complete
|
|
42
|
+
</button>
|
|
43
|
+
)}
|
|
44
|
+
{isPending && "(Applying)"}
|
|
45
|
+
{data && "(Action completed successfully)"}
|
|
46
|
+
</div>
|
|
47
|
+
{error && (
|
|
48
|
+
<div>
|
|
49
|
+
An error occurred:
|
|
50
|
+
<pre>{JSON.stringify(error, null, 2)}</pre>
|
|
51
|
+
</div>
|
|
52
|
+
)}
|
|
53
|
+
</div>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Return Values
|
|
59
|
+
|
|
60
|
+
- `applyAction` - Function to execute the action (accepts single args object or array for batch)
|
|
61
|
+
- `data` - Return value from the last successful action execution
|
|
62
|
+
- `error` - Error object (see error handling below)
|
|
63
|
+
- `isPending` - True while action is executing
|
|
64
|
+
- `isValidating` - True while validation is in progress
|
|
65
|
+
- `validateAction` - Function to validate without executing
|
|
66
|
+
- `validationResult` - Result of last validation
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Error Handling
|
|
71
|
+
|
|
72
|
+
The `error` object has the following structure:
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
{
|
|
76
|
+
actionValidation?: ActionValidationError;
|
|
77
|
+
unknown?: unknown;
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`ActionValidationError` extends `Error` and has:
|
|
82
|
+
- `message` - Error message string
|
|
83
|
+
- `validation` - Full validation response from server
|
|
84
|
+
|
|
85
|
+
Example:
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
import { $Actions, Todo } from "@my/osdk";
|
|
89
|
+
import { useOsdkAction } from "@osdk/react/experimental";
|
|
90
|
+
|
|
91
|
+
function TodoActionWithErrorHandling({ todo }: { todo: Todo.OsdkInstance }) {
|
|
92
|
+
const { applyAction, error, isPending } = useOsdkAction($Actions.completeTodo);
|
|
93
|
+
|
|
94
|
+
const onClick = async () => {
|
|
95
|
+
try {
|
|
96
|
+
await applyAction({ todo, isComplete: true });
|
|
97
|
+
} catch (e) {
|
|
98
|
+
console.error("Action failed", e);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<div>
|
|
104
|
+
<button onClick={onClick} disabled={isPending}>
|
|
105
|
+
Complete Todo
|
|
106
|
+
</button>
|
|
107
|
+
|
|
108
|
+
{error?.actionValidation && (
|
|
109
|
+
<div style={{ color: "red" }}>
|
|
110
|
+
Validation failed: {JSON.stringify(error.actionValidation.validation)}
|
|
111
|
+
</div>
|
|
112
|
+
)}
|
|
113
|
+
|
|
114
|
+
{error?.unknown && (
|
|
115
|
+
<div style={{ color: "red" }}>
|
|
116
|
+
An unexpected error occurred: {String(error.unknown)}
|
|
117
|
+
</div>
|
|
118
|
+
)}
|
|
119
|
+
</div>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Validation
|
|
127
|
+
|
|
128
|
+
Validate action parameters without executing using `validateAction`.
|
|
129
|
+
|
|
130
|
+
```tsx
|
|
131
|
+
import { $Actions } from "@my/osdk";
|
|
132
|
+
import { useOsdkAction } from "@osdk/react/experimental";
|
|
133
|
+
import { useState } from "react";
|
|
134
|
+
|
|
135
|
+
function TodoForm() {
|
|
136
|
+
const [title, setTitle] = useState("");
|
|
137
|
+
const [assignee, setAssignee] = useState("");
|
|
138
|
+
|
|
139
|
+
const {
|
|
140
|
+
applyAction,
|
|
141
|
+
validateAction,
|
|
142
|
+
isValidating,
|
|
143
|
+
validationResult,
|
|
144
|
+
isPending,
|
|
145
|
+
error,
|
|
146
|
+
} = useOsdkAction($Actions.createTodo);
|
|
147
|
+
|
|
148
|
+
const handleTitleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
149
|
+
const newTitle = e.target.value;
|
|
150
|
+
setTitle(newTitle);
|
|
151
|
+
validateAction({ title: newTitle, assignee });
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const handleAssigneeChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
155
|
+
const newAssignee = e.target.value;
|
|
156
|
+
setAssignee(newAssignee);
|
|
157
|
+
validateAction({ title, assignee: newAssignee });
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const handleSubmit = async (e: React.FormEvent) => {
|
|
161
|
+
e.preventDefault();
|
|
162
|
+
if (validationResult?.result === "VALID") {
|
|
163
|
+
await applyAction({ title, assignee });
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
return (
|
|
168
|
+
<form onSubmit={handleSubmit}>
|
|
169
|
+
<input
|
|
170
|
+
type="text"
|
|
171
|
+
value={title}
|
|
172
|
+
onChange={handleTitleChange}
|
|
173
|
+
placeholder="Todo title"
|
|
174
|
+
/>
|
|
175
|
+
<input
|
|
176
|
+
type="text"
|
|
177
|
+
value={assignee}
|
|
178
|
+
onChange={handleAssigneeChange}
|
|
179
|
+
placeholder="Assignee"
|
|
180
|
+
/>
|
|
181
|
+
|
|
182
|
+
{isValidating && <span>Validating...</span>}
|
|
183
|
+
|
|
184
|
+
{validationResult?.result === "INVALID" && (
|
|
185
|
+
<div style={{ color: "red" }}>
|
|
186
|
+
Invalid: {JSON.stringify(validationResult)}
|
|
187
|
+
</div>
|
|
188
|
+
)}
|
|
189
|
+
|
|
190
|
+
<button
|
|
191
|
+
type="submit"
|
|
192
|
+
disabled={isPending || isValidating || validationResult?.result !== "VALID"}
|
|
193
|
+
>
|
|
194
|
+
Create Todo
|
|
195
|
+
</button>
|
|
196
|
+
|
|
197
|
+
{error?.actionValidation && (
|
|
198
|
+
<div style={{ color: "red" }}>
|
|
199
|
+
Validation error: {error.actionValidation.message}
|
|
200
|
+
</div>
|
|
201
|
+
)}
|
|
202
|
+
</form>
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Key features:
|
|
208
|
+
|
|
209
|
+
- `validateAction` - Validates action parameters without executing
|
|
210
|
+
- `isValidating` - True while validation is in progress
|
|
211
|
+
- `validationResult` - Contains `{ result: "VALID" | "INVALID", ... }`
|
|
212
|
+
- Calling `validateAction` while a previous validation is in progress cancels the previous one
|
|
213
|
+
- Validation and execution are mutually exclusive
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Batch Actions
|
|
218
|
+
|
|
219
|
+
Apply the same action to multiple items in a single call:
|
|
220
|
+
|
|
221
|
+
```tsx
|
|
222
|
+
import { $Actions, Todo } from "@my/osdk";
|
|
223
|
+
import { useOsdkAction } from "@osdk/react/experimental";
|
|
224
|
+
import { useCallback } from "react";
|
|
225
|
+
|
|
226
|
+
function BulkCompleteButton({ todos }: { todos: Todo.OsdkInstance[] }) {
|
|
227
|
+
const { applyAction, isPending } = useOsdkAction($Actions.completeTodo);
|
|
228
|
+
|
|
229
|
+
const onClick = useCallback(() => {
|
|
230
|
+
applyAction(
|
|
231
|
+
todos.map(todo => ({
|
|
232
|
+
todo: todo,
|
|
233
|
+
isComplete: true,
|
|
234
|
+
})),
|
|
235
|
+
);
|
|
236
|
+
}, [applyAction, todos]);
|
|
237
|
+
|
|
238
|
+
return (
|
|
239
|
+
<button onClick={onClick} disabled={isPending}>
|
|
240
|
+
Complete All ({todos.length})
|
|
241
|
+
</button>
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## Optimistic Updates
|
|
249
|
+
|
|
250
|
+
Apply changes to the cache immediately while waiting for the server response.
|
|
251
|
+
|
|
252
|
+
```tsx
|
|
253
|
+
import { $Actions, Todo } from "@my/osdk";
|
|
254
|
+
import { useOsdkAction, useOsdkObject } from "@osdk/react/experimental";
|
|
255
|
+
import { useCallback } from "react";
|
|
256
|
+
|
|
257
|
+
function TodoView({ todo }: { todo: Todo.OsdkInstance }) {
|
|
258
|
+
const { isLoading, isOptimistic } = useOsdkObject(todo);
|
|
259
|
+
const { applyAction, error, isPending } = useOsdkAction($Actions.completeTodo);
|
|
260
|
+
|
|
261
|
+
const onClick = useCallback(() => {
|
|
262
|
+
applyAction({
|
|
263
|
+
todo: todo,
|
|
264
|
+
isComplete: true,
|
|
265
|
+
|
|
266
|
+
$optimisticUpdate: (ou) => {
|
|
267
|
+
ou.updateObject(todo.$clone({ isComplete: true }));
|
|
268
|
+
},
|
|
269
|
+
});
|
|
270
|
+
}, [applyAction, todo]);
|
|
271
|
+
|
|
272
|
+
return (
|
|
273
|
+
<div>
|
|
274
|
+
{todo.title}
|
|
275
|
+
{todo.isComplete === false && !isOptimistic && (
|
|
276
|
+
<button onClick={onClick} disabled={isPending}>Mark Complete</button>
|
|
277
|
+
)}
|
|
278
|
+
{isPending && "(Saving)"}
|
|
279
|
+
{isLoading && "(Loading)"}
|
|
280
|
+
{isOptimistic && "(Optimistic)"}
|
|
281
|
+
{error && (
|
|
282
|
+
<div style={{ color: "red" }}>
|
|
283
|
+
{error.actionValidation?.message ?? String(error.unknown)}
|
|
284
|
+
</div>
|
|
285
|
+
)}
|
|
286
|
+
</div>
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### How Optimistic Updates Work
|
|
292
|
+
|
|
293
|
+
1. When you call `applyAction` with `$optimisticUpdate`, the cache is updated immediately
|
|
294
|
+
2. The UI shows the optimistic state (tracked via `isOptimistic`)
|
|
295
|
+
3. If the action succeeds, the cache is refreshed with server data
|
|
296
|
+
4. If the action fails, the optimistic changes are rolled back automatically
|
|
297
|
+
|
|
298
|
+
### Optimistic Update API
|
|
299
|
+
|
|
300
|
+
The `$optimisticUpdate` callback receives an object with the following methods:
|
|
301
|
+
|
|
302
|
+
```tsx
|
|
303
|
+
$optimisticUpdate: (ou) => {
|
|
304
|
+
ou.updateObject(todo.$clone({ isComplete: true }));
|
|
305
|
+
ou.updateObject(anotherObject.$clone({ ... }));
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
:::note The `$clone` method
|
|
310
|
+
Every OSDK object instance has a `$clone()` method that creates a new object with modified properties. This is essential for optimistic updates because OSDK objects are immutable.
|
|
311
|
+
|
|
312
|
+
```tsx
|
|
313
|
+
// Create a modified copy without mutating the original
|
|
314
|
+
const completedTodo = todo.$clone({ isComplete: true });
|
|
315
|
+
|
|
316
|
+
// Clone with multiple property changes
|
|
317
|
+
const updatedTodo = todo.$clone({
|
|
318
|
+
title: "New Title",
|
|
319
|
+
priority: "high",
|
|
320
|
+
});
|
|
321
|
+
```
|
|
322
|
+
:::
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
## useDebouncedCallback
|
|
327
|
+
|
|
328
|
+
*Experimental - import from `@osdk/react/experimental`*
|
|
329
|
+
|
|
330
|
+
Debounce callback functions for auto-save patterns or expensive operations.
|
|
331
|
+
|
|
332
|
+
### Basic Usage
|
|
333
|
+
|
|
334
|
+
```tsx
|
|
335
|
+
import { useDebouncedCallback } from "@osdk/react/experimental";
|
|
336
|
+
import { useState } from "react";
|
|
337
|
+
|
|
338
|
+
function SearchableList({ onSearch }: { onSearch: (query: string) => void }) {
|
|
339
|
+
const [query, setQuery] = useState("");
|
|
340
|
+
|
|
341
|
+
const debouncedSearch = useDebouncedCallback((q: string) => {
|
|
342
|
+
onSearch(q);
|
|
343
|
+
}, 500);
|
|
344
|
+
|
|
345
|
+
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
346
|
+
const value = e.target.value;
|
|
347
|
+
setQuery(value);
|
|
348
|
+
debouncedSearch(value);
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
return (
|
|
352
|
+
<input
|
|
353
|
+
value={query}
|
|
354
|
+
onChange={handleChange}
|
|
355
|
+
placeholder="Search..."
|
|
356
|
+
/>
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### Auto-Save Pattern
|
|
362
|
+
|
|
363
|
+
Combine with actions for auto-saving:
|
|
364
|
+
|
|
365
|
+
```tsx
|
|
366
|
+
import { $Actions, Todo } from "@my/osdk";
|
|
367
|
+
import { useDebouncedCallback, useOsdkAction } from "@osdk/react/experimental";
|
|
368
|
+
import { useState } from "react";
|
|
369
|
+
|
|
370
|
+
function AutoSaveTodo({ todo }: { todo: Todo.OsdkInstance }) {
|
|
371
|
+
const [title, setTitle] = useState(todo.title);
|
|
372
|
+
const { applyAction } = useOsdkAction($Actions.updateTodo);
|
|
373
|
+
|
|
374
|
+
const debouncedSave = useDebouncedCallback((newTitle: string) => {
|
|
375
|
+
applyAction({
|
|
376
|
+
todo,
|
|
377
|
+
title: newTitle,
|
|
378
|
+
$optimisticUpdate: (ou) => {
|
|
379
|
+
ou.updateObject(todo.$clone({ title: newTitle }));
|
|
380
|
+
},
|
|
381
|
+
});
|
|
382
|
+
}, 1000);
|
|
383
|
+
|
|
384
|
+
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
385
|
+
const newTitle = e.target.value;
|
|
386
|
+
setTitle(newTitle);
|
|
387
|
+
debouncedSave(newTitle);
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
return (
|
|
391
|
+
<input
|
|
392
|
+
value={title}
|
|
393
|
+
onChange={handleChange}
|
|
394
|
+
placeholder="Click to edit title..."
|
|
395
|
+
/>
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
### Debounced Callback Methods
|
|
401
|
+
|
|
402
|
+
The returned function has utility methods:
|
|
403
|
+
|
|
404
|
+
```tsx
|
|
405
|
+
import { useDebouncedCallback } from "@osdk/react/experimental";
|
|
406
|
+
|
|
407
|
+
const debouncedFn = useDebouncedCallback((value: string) => {
|
|
408
|
+
console.log("Called with:", value);
|
|
409
|
+
}, 500);
|
|
410
|
+
|
|
411
|
+
debouncedFn("hello");
|
|
412
|
+
debouncedFn.cancel();
|
|
413
|
+
debouncedFn.flush();
|
|
414
|
+
```
|