@faasjs/react 8.0.0-beta.14 → 8.0.0-beta.15
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 +0 -41
- package/dist/index.cjs +45 -38
- package/dist/index.d.ts +18 -18
- package/dist/index.mjs +45 -38
- package/package.json +3 -6
package/README.md
CHANGED
|
@@ -1,46 +1,5 @@
|
|
|
1
1
|
# @faasjs/react
|
|
2
2
|
|
|
3
|
-
React plugin for FaasJS.
|
|
4
|
-
|
|
5
|
-
[](https://github.com/faasjs/faasjs/blob/main/packages/react/LICENSE)
|
|
6
|
-
[](https://www.npmjs.com/package/@faasjs/react)
|
|
7
|
-
|
|
8
|
-
Includes browser client utilities (`FaasBrowserClient`, `ResponseError`, `setMock`) and React helpers.
|
|
9
|
-
|
|
10
|
-
## Features
|
|
11
|
-
|
|
12
|
-
- Support [FaasJS Request Specifications](https://faasjs.com/guide/request-spec.html).
|
|
13
|
-
- Support global and per-request configurations.
|
|
14
|
-
- Compatible with [why-did-you-render](https://github.com/welldone-software/why-did-you-render).
|
|
15
|
-
- Additional React functions:
|
|
16
|
-
- Utils:
|
|
17
|
-
- `equal`: Compare two values for deep equality.
|
|
18
|
-
- `createSplittingContext`: Create a context for code splitting.
|
|
19
|
-
- `useSplittingState`: Create splitting states.
|
|
20
|
-
- Hooks:
|
|
21
|
-
- `useEqualMemoize`: Memoize a value with deep equality.
|
|
22
|
-
- `useEqualEffect`: Run an effect with deep equality.
|
|
23
|
-
- `useEqualMemo`: Memoize a value with deep equality.
|
|
24
|
-
- `useEqualCallback`: Memoize a callback with deep equality.
|
|
25
|
-
- `useConstant`: Create a constant value with hooks.
|
|
26
|
-
- `usePrevious`: Get the previous value of a state.
|
|
27
|
-
- `useStateRef`: Create a state with a ref.
|
|
28
|
-
- Components:
|
|
29
|
-
- `OptionalWrapper`: Render a component optionally.
|
|
30
|
-
- `ErrorBoundary`: Catch errors in the component tree.
|
|
31
|
-
- Fetch Data:
|
|
32
|
-
- `faas`: Fetch data from FaasJS.
|
|
33
|
-
- `useFaas`: Fetch data from FaasJS with hooks.
|
|
34
|
-
- `useFaasStream`: Fetch streaming data from FaasJS with hooks.
|
|
35
|
-
- `FaasDataWrapper`: Fetch data from FaasJS with a wrapper component.
|
|
36
|
-
- `withFaasData`: Fetch data from FaasJS using a higher-order component (HOC).
|
|
37
|
-
|
|
38
|
-
## Install
|
|
39
|
-
|
|
40
|
-
```sh
|
|
41
|
-
npm install @faasjs/react react
|
|
42
|
-
```
|
|
43
|
-
|
|
44
3
|
## Functions
|
|
45
4
|
|
|
46
5
|
- [createSplittingContext](functions/createSplittingContext.md)
|
package/dist/index.cjs
CHANGED
|
@@ -39,7 +39,7 @@ function generateId(prefix = "", length = 18) {
|
|
|
39
39
|
* @param {ResponseProps<T>} [props] - Response properties including status, headers, body, and data.
|
|
40
40
|
* All properties are optional with sensible defaults.
|
|
41
41
|
*
|
|
42
|
-
*
|
|
42
|
+
* Notes:
|
|
43
43
|
* - status defaults to 200 if data or body is present, 204 otherwise
|
|
44
44
|
* - body is automatically populated from data if not explicitly provided
|
|
45
45
|
* - headers defaults to an empty object if not provided
|
|
@@ -157,7 +157,7 @@ var Response = class {
|
|
|
157
157
|
* including HTTP status code, response headers, response body, and the original error.
|
|
158
158
|
*
|
|
159
159
|
* @class ResponseError
|
|
160
|
-
* @
|
|
160
|
+
* @augments Error
|
|
161
161
|
*
|
|
162
162
|
* @property {number} status - The HTTP status code of the failed response. Defaults to 500 if not provided.
|
|
163
163
|
* @property {ResponseHeaders} headers - The response headers from the failed request.
|
|
@@ -238,7 +238,7 @@ var Response = class {
|
|
|
238
238
|
* })
|
|
239
239
|
* ```
|
|
240
240
|
*
|
|
241
|
-
*
|
|
241
|
+
* Notes:
|
|
242
242
|
* - ResponseError is automatically thrown by the action method when the server returns an error (status >= 400)
|
|
243
243
|
* - The error message from server responses is extracted from body.error.message if available
|
|
244
244
|
* - When created from an Error object, the original error is preserved in the originalError property
|
|
@@ -261,7 +261,7 @@ var ResponseError = class extends Error {
|
|
|
261
261
|
message: data,
|
|
262
262
|
...options
|
|
263
263
|
};
|
|
264
|
-
else if (data instanceof Error || data
|
|
264
|
+
else if (data instanceof Error || typeof data === "object" && data !== null && typeof data.constructor?.name === "string" && data.constructor.name.includes("Error")) props = {
|
|
265
265
|
message: data.message,
|
|
266
266
|
originalError: data,
|
|
267
267
|
...options
|
|
@@ -344,7 +344,7 @@ function setMock(handler) {
|
|
|
344
344
|
* - Streaming support for large responses
|
|
345
345
|
* - Multiple instance support with unique IDs
|
|
346
346
|
*
|
|
347
|
-
*
|
|
347
|
+
* Notes:
|
|
348
348
|
* - All requests are POST requests by default
|
|
349
349
|
* - Automatically adds X-FaasJS-Request-Id header for request tracking
|
|
350
350
|
* - baseUrl must end with '/' (will throw Error if not)
|
|
@@ -488,7 +488,7 @@ var FaasBrowserClient = class {
|
|
|
488
488
|
* @throws {ResponseError} When the server returns an error response (status >= 400 or body.error exists)
|
|
489
489
|
* @throws {NetworkError} When network request fails
|
|
490
490
|
*
|
|
491
|
-
*
|
|
491
|
+
* Notes:
|
|
492
492
|
* - All requests are POST requests by default
|
|
493
493
|
* - Action path is automatically converted to lowercase
|
|
494
494
|
* - A unique request ID is generated for each request and sent in X-FaasJS-Request-Id header
|
|
@@ -647,7 +647,7 @@ var FaasBrowserClient = class {
|
|
|
647
647
|
headers,
|
|
648
648
|
body
|
|
649
649
|
}));
|
|
650
|
-
} catch
|
|
650
|
+
} catch {
|
|
651
651
|
return Promise.reject(new ResponseError({
|
|
652
652
|
message: res,
|
|
653
653
|
status: response.status,
|
|
@@ -733,13 +733,18 @@ function equal(a, b) {
|
|
|
733
733
|
* @returns The memoized value.
|
|
734
734
|
*/
|
|
735
735
|
function useEqualMemoize(value) {
|
|
736
|
+
const ref = (0, react.useRef)(value);
|
|
737
|
+
if (!equal(value, ref.current)) ref.current = value;
|
|
738
|
+
return ref.current;
|
|
739
|
+
}
|
|
740
|
+
function useEqualSignal(value) {
|
|
736
741
|
const ref = (0, react.useRef)(value);
|
|
737
742
|
const signalRef = (0, react.useRef)(0);
|
|
738
743
|
if (!equal(value, ref.current)) {
|
|
739
744
|
ref.current = value;
|
|
740
745
|
signalRef.current += 1;
|
|
741
746
|
}
|
|
742
|
-
return
|
|
747
|
+
return signalRef.current;
|
|
743
748
|
}
|
|
744
749
|
/**
|
|
745
750
|
* Custom hook that works like `useEffect` but uses deep comparison on dependencies.
|
|
@@ -749,7 +754,7 @@ function useEqualMemoize(value) {
|
|
|
749
754
|
* @returns The result of the `useEffect` hook with memoized dependencies.
|
|
750
755
|
*/
|
|
751
756
|
function useEqualEffect(callback, dependencies) {
|
|
752
|
-
return (0, react.useEffect)(callback,
|
|
757
|
+
return (0, react.useEffect)(callback, [useEqualSignal(dependencies)]);
|
|
753
758
|
}
|
|
754
759
|
/**
|
|
755
760
|
* Custom hook that works like `useMemo` but uses deep comparison on dependencies.
|
|
@@ -759,7 +764,12 @@ function useEqualEffect(callback, dependencies) {
|
|
|
759
764
|
* @returns The result of the `useMemo` hook with memoized dependencies.
|
|
760
765
|
*/
|
|
761
766
|
function useEqualMemo(callback, dependencies) {
|
|
762
|
-
|
|
767
|
+
const signal = useEqualSignal(dependencies);
|
|
768
|
+
const callbackRef = (0, react.useRef)(callback);
|
|
769
|
+
callbackRef.current = callback;
|
|
770
|
+
return (0, react.useMemo)(() => {
|
|
771
|
+
return callbackRef.current();
|
|
772
|
+
}, [signal]);
|
|
763
773
|
}
|
|
764
774
|
/**
|
|
765
775
|
* Custom hook that works like `useCallback` but uses deep comparison on dependencies.
|
|
@@ -769,7 +779,7 @@ function useEqualMemo(callback, dependencies) {
|
|
|
769
779
|
* @returns The result of the `useCallback` hook with memoized dependencies.
|
|
770
780
|
*/
|
|
771
781
|
function useEqualCallback(callback, dependencies) {
|
|
772
|
-
return (0, react.useCallback)((...args) => callback(...args),
|
|
782
|
+
return (0, react.useCallback)((...args) => callback(...args), [useEqualSignal(dependencies)]);
|
|
773
783
|
}
|
|
774
784
|
//#endregion
|
|
775
785
|
//#region src/FaasDataWrapper.tsx
|
|
@@ -871,7 +881,8 @@ function useFaas(action, defaultParams, options = {}) {
|
|
|
871
881
|
const nextData = r.data;
|
|
872
882
|
setFails(0);
|
|
873
883
|
setError(null);
|
|
874
|
-
options.setData
|
|
884
|
+
if (options.setData) options.setData(nextData);
|
|
885
|
+
else localSetData(nextData);
|
|
875
886
|
setLoading(false);
|
|
876
887
|
for (const { resolve } of pendingReloadsRef.current.values()) resolve(nextData);
|
|
877
888
|
pendingReloadsRef.current.clear();
|
|
@@ -1349,34 +1360,30 @@ async function validValues(rules, items, values, lang) {
|
|
|
1349
1360
|
//#region src/Form/Footer.tsx
|
|
1350
1361
|
function FormFooter() {
|
|
1351
1362
|
const { submitting, setSubmitting, onSubmit, valuesRef, Elements, items, setErrors, lang, rules } = useFormContext();
|
|
1352
|
-
const
|
|
1353
|
-
|
|
1354
|
-
setErrors({});
|
|
1355
|
-
const errors = await validValues(rules, items, valuesRef.current, lang);
|
|
1356
|
-
if (Object.keys(errors).length) {
|
|
1357
|
-
setErrors(errors);
|
|
1358
|
-
setSubmitting(false);
|
|
1359
|
-
return;
|
|
1360
|
-
}
|
|
1361
|
-
onSubmit(valuesRef.current).finally(() => setSubmitting(false));
|
|
1362
|
-
}, [
|
|
1363
|
-
setSubmitting,
|
|
1364
|
-
setErrors,
|
|
1365
|
-
rules,
|
|
1366
|
-
items,
|
|
1367
|
-
lang,
|
|
1368
|
-
onSubmit
|
|
1369
|
-
]);
|
|
1370
|
-
return (0, react.useMemo)(() => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Elements.Button, {
|
|
1363
|
+
const Button = Elements.Button;
|
|
1364
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
1371
1365
|
submitting,
|
|
1372
|
-
submit:
|
|
1366
|
+
submit: (0, react.useCallback)(async () => {
|
|
1367
|
+
setSubmitting(true);
|
|
1368
|
+
setErrors({});
|
|
1369
|
+
const errors = await validValues(rules, items, valuesRef.current, lang);
|
|
1370
|
+
if (Object.keys(errors).length) {
|
|
1371
|
+
setErrors(errors);
|
|
1372
|
+
setSubmitting(false);
|
|
1373
|
+
return;
|
|
1374
|
+
}
|
|
1375
|
+
onSubmit(valuesRef.current).finally(() => setSubmitting(false));
|
|
1376
|
+
}, [
|
|
1377
|
+
setSubmitting,
|
|
1378
|
+
setErrors,
|
|
1379
|
+
rules,
|
|
1380
|
+
items,
|
|
1381
|
+
valuesRef,
|
|
1382
|
+
lang,
|
|
1383
|
+
onSubmit
|
|
1384
|
+
]),
|
|
1373
1385
|
children: lang.submit
|
|
1374
|
-
})
|
|
1375
|
-
submitting,
|
|
1376
|
-
handleSubmit,
|
|
1377
|
-
lang.submit,
|
|
1378
|
-
Elements.Button
|
|
1379
|
-
]);
|
|
1386
|
+
});
|
|
1380
1387
|
}
|
|
1381
1388
|
FormFooter.displayName = "FormFooter";
|
|
1382
1389
|
//#endregion
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { FaasAction, FaasAction as FaasAction$1, FaasActionUnionType, FaasActionUnionType as FaasActionUnionType$1, FaasData, FaasData as FaasData$1, FaasParams, FaasParams as FaasParams$1 } from "@faasjs/types";
|
|
1
2
|
import * as react from "react";
|
|
2
3
|
import { Component, ComponentProps, ComponentType, Dispatch, ErrorInfo, JSX, JSXElementConstructor, ReactElement, ReactNode, RefObject, SetStateAction } from "react";
|
|
3
4
|
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
4
|
-
import { FaasAction, FaasAction as FaasAction$1, FaasActionUnionType, FaasActionUnionType as FaasActionUnionType$1, FaasData, FaasData as FaasData$1, FaasParams, FaasParams as FaasParams$1 } from "@faasjs/types";
|
|
5
5
|
|
|
6
6
|
//#region src/generateId.d.ts
|
|
7
7
|
/**
|
|
@@ -24,7 +24,7 @@ declare function generateId(prefix?: string, length?: number): string;
|
|
|
24
24
|
* Ensures that base URLs used in FaasJS requests always have a trailing '/' character,
|
|
25
25
|
* which is required for proper URL construction when appending action paths.
|
|
26
26
|
*
|
|
27
|
-
*
|
|
27
|
+
* Notes:
|
|
28
28
|
* - Type only accepts strings ending with '/' (e.g., 'https://api.example.com/', '/')
|
|
29
29
|
* - Strings without trailing '/' will fail TypeScript type checking
|
|
30
30
|
* - Used by FaasBrowserClient constructor and Options type
|
|
@@ -41,7 +41,7 @@ type BaseUrl = `${string}/`;
|
|
|
41
41
|
* Extends the standard RequestInit interface with FaasJS-specific options for
|
|
42
42
|
* customizing request behavior, adding request hooks, and overriding defaults.
|
|
43
43
|
*
|
|
44
|
-
*
|
|
44
|
+
* Notes:
|
|
45
45
|
* - Options can be provided at client creation (defaultOptions) or per-request
|
|
46
46
|
* - Per-request options override client default options
|
|
47
47
|
* - headers are merged: per-request headers override default headers
|
|
@@ -73,7 +73,7 @@ type BaseUrl = `${string}/`;
|
|
|
73
73
|
* Useful for processing large data incrementally or working with binary data streams.
|
|
74
74
|
* When false or undefined, returns a wrapped Response with automatic JSON parsing.
|
|
75
75
|
*
|
|
76
|
-
* @
|
|
76
|
+
* @augments RequestInit
|
|
77
77
|
* @see FaasBrowserClient for client creation
|
|
78
78
|
* @see Response for response object structure
|
|
79
79
|
*/
|
|
@@ -103,7 +103,7 @@ type Options = RequestInit & {
|
|
|
103
103
|
* @property {string} [key] - Dynamic string keys for header names (e.g., 'Content-Type', 'Authorization').
|
|
104
104
|
* Values must be strings. Multiple values for the same key are not supported.
|
|
105
105
|
*
|
|
106
|
-
*
|
|
106
|
+
* Notes:
|
|
107
107
|
* - Headers are case-insensitive in HTTP but stored with exact casing in this object
|
|
108
108
|
* - Common headers include: Content-Type, Authorization, X-Request-Id, X-Custom-Header
|
|
109
109
|
* - No support for multi-value headers (use comma-separated values instead)
|
|
@@ -131,7 +131,7 @@ type ResponseHeaders = {
|
|
|
131
131
|
*
|
|
132
132
|
* @returns {Promise<Response<FaasData<PathOrData>> | Response>} - A Promise resolving to a Response object
|
|
133
133
|
*
|
|
134
|
-
*
|
|
134
|
+
* Notes:
|
|
135
135
|
* - Used internally by FaasBrowserClient.action method
|
|
136
136
|
* - Provides type-safe action method signature
|
|
137
137
|
* - Return type includes both typed and untyped Response variants
|
|
@@ -163,7 +163,7 @@ type FaasBrowserClientAction = <PathOrData extends FaasActionUnionType$1>(action
|
|
|
163
163
|
* @property {T} [data] - The parsed JSON data to include in the response.
|
|
164
164
|
* Optional: contains the response payload when JSON data is provided.
|
|
165
165
|
*
|
|
166
|
-
*
|
|
166
|
+
* Notes:
|
|
167
167
|
* - All properties are optional
|
|
168
168
|
* - At least one of data or body should be provided for meaningful responses
|
|
169
169
|
* - The Response class automatically defaults status to 200 or 204 based on content
|
|
@@ -199,7 +199,7 @@ type ResponseProps<T = any> = {
|
|
|
199
199
|
* @param {ResponseProps<T>} [props] - Response properties including status, headers, body, and data.
|
|
200
200
|
* All properties are optional with sensible defaults.
|
|
201
201
|
*
|
|
202
|
-
*
|
|
202
|
+
* Notes:
|
|
203
203
|
* - status defaults to 200 if data or body is present, 204 otherwise
|
|
204
204
|
* - body is automatically populated from data if not explicitly provided
|
|
205
205
|
* - headers defaults to an empty object if not provided
|
|
@@ -318,7 +318,7 @@ type ResponseErrorProps = {
|
|
|
318
318
|
* including HTTP status code, response headers, response body, and the original error.
|
|
319
319
|
*
|
|
320
320
|
* @class ResponseError
|
|
321
|
-
* @
|
|
321
|
+
* @augments Error
|
|
322
322
|
*
|
|
323
323
|
* @property {number} status - The HTTP status code of the failed response. Defaults to 500 if not provided.
|
|
324
324
|
* @property {ResponseHeaders} headers - The response headers from the failed request.
|
|
@@ -399,7 +399,7 @@ type ResponseErrorProps = {
|
|
|
399
399
|
* })
|
|
400
400
|
* ```
|
|
401
401
|
*
|
|
402
|
-
*
|
|
402
|
+
* Notes:
|
|
403
403
|
* - ResponseError is automatically thrown by the action method when the server returns an error (status >= 400)
|
|
404
404
|
* - The error message from server responses is extracted from body.error.message if available
|
|
405
405
|
* - When created from an Error object, the original error is preserved in the originalError property
|
|
@@ -441,7 +441,7 @@ declare class ResponseError extends Error {
|
|
|
441
441
|
* - void: Returns an empty response (204 No Content)
|
|
442
442
|
* - Error: Throws ResponseError when returning an Error object
|
|
443
443
|
*
|
|
444
|
-
*
|
|
444
|
+
* Notes:
|
|
445
445
|
* - Used by setMock() function to mock API calls during tests
|
|
446
446
|
* - Affects all FaasBrowserClient instances when set globally
|
|
447
447
|
* - Can return different responses based on action or params
|
|
@@ -568,7 +568,7 @@ declare function setMock(handler: MockHandler | ResponseProps | Response | null)
|
|
|
568
568
|
* - Streaming support for large responses
|
|
569
569
|
* - Multiple instance support with unique IDs
|
|
570
570
|
*
|
|
571
|
-
*
|
|
571
|
+
* Notes:
|
|
572
572
|
* - All requests are POST requests by default
|
|
573
573
|
* - Automatically adds X-FaasJS-Request-Id header for request tracking
|
|
574
574
|
* - baseUrl must end with '/' (will throw Error if not)
|
|
@@ -706,7 +706,7 @@ declare class FaasBrowserClient {
|
|
|
706
706
|
* @throws {ResponseError} When the server returns an error response (status >= 400 or body.error exists)
|
|
707
707
|
* @throws {NetworkError} When network request fails
|
|
708
708
|
*
|
|
709
|
-
*
|
|
709
|
+
* Notes:
|
|
710
710
|
* - All requests are POST requests by default
|
|
711
711
|
* - Action path is automatically converted to lowercase
|
|
712
712
|
* - A unique request ID is generated for each request and sent in X-FaasJS-Request-Id header
|
|
@@ -1228,13 +1228,13 @@ type FormContextProps<Values extends Record<string, any> = Record<string, any>,
|
|
|
1228
1228
|
setErrors: Dispatch<SetStateAction<Record<string, Error>>>;
|
|
1229
1229
|
valuesRef: RefObject<Values>;
|
|
1230
1230
|
};
|
|
1231
|
-
declare const FormContextProvider: <NewT extends FormContextProps<Record<string, any>, FormElementTypes, FormRules> = FormContextProps<Record<string, any>, FormElementTypes, FormRules>>(props: {
|
|
1231
|
+
declare const FormContextProvider: <NewT extends FormContextProps<Record<string, any>, FormElementTypes, FormRules> = FormContextProps<Record<string, any>, FormElementTypes, FormRules>>(this: void, props: {
|
|
1232
1232
|
value?: Partial<NewT>;
|
|
1233
1233
|
children: react.ReactNode;
|
|
1234
1234
|
memo?: true | any[];
|
|
1235
1235
|
initializeStates?: Partial<NewT>;
|
|
1236
1236
|
}) => react.ReactNode;
|
|
1237
|
-
declare const useFormContext: <NewT extends FormContextProps<Record<string, any>, FormElementTypes, FormRules> = FormContextProps<Record<string, any>, FormElementTypes, FormRules>>() => Readonly<NewT>;
|
|
1237
|
+
declare const useFormContext: <NewT extends FormContextProps<Record<string, any>, FormElementTypes, FormRules> = FormContextProps<Record<string, any>, FormElementTypes, FormRules>>(this: void) => Readonly<NewT>;
|
|
1238
1238
|
//#endregion
|
|
1239
1239
|
//#region src/OptionalWrapper.d.ts
|
|
1240
1240
|
type OptionalWrapperProps<TWrapper extends ComponentType<{
|
|
@@ -1337,7 +1337,7 @@ declare function createSplittingContext<T extends Record<string, any>>(defaultVa
|
|
|
1337
1337
|
* }
|
|
1338
1338
|
* ```
|
|
1339
1339
|
*/
|
|
1340
|
-
Provider<NewT extends T = T>(props: {
|
|
1340
|
+
Provider<NewT extends T = T>(this: void, props: {
|
|
1341
1341
|
value?: Partial<NewT>;
|
|
1342
1342
|
children: ReactNode;
|
|
1343
1343
|
/**
|
|
@@ -1378,7 +1378,7 @@ declare function createSplittingContext<T extends Record<string, any>>(defaultVa
|
|
|
1378
1378
|
* }
|
|
1379
1379
|
* ```
|
|
1380
1380
|
*/
|
|
1381
|
-
use: <NewT extends T = T>() => Readonly<NewT>;
|
|
1381
|
+
use: <NewT extends T = T>(this: void) => Readonly<NewT>;
|
|
1382
1382
|
};
|
|
1383
1383
|
//#endregion
|
|
1384
1384
|
//#region src/splittingState.d.ts
|
|
@@ -1487,4 +1487,4 @@ declare function usePrevious<T = any>(value: T): T | undefined;
|
|
|
1487
1487
|
*/
|
|
1488
1488
|
declare function useStateRef<T = any>(initialValue?: T): [T | null, Dispatch<SetStateAction<T | null>>, RefObject<T | null>];
|
|
1489
1489
|
//#endregion
|
|
1490
|
-
export { BaseUrl, ErrorBoundary, ErrorBoundaryProps, ErrorChildrenProps, type FaasAction, type FaasActionUnionType, FaasBrowserClient, FaasBrowserClientAction, type FaasData, FaasDataInjection, FaasDataWrapper, FaasDataWrapperProps, FaasDataWrapperRef, type FaasParams, FaasReactClient, FaasReactClientInstance, FaasReactClientOptions, FormContainer as Form, type FormButtonElementProps, FormContextProps, FormContextProvider, FormDefaultElements, FormDefaultLang, FormDefaultRules, FormDefaultRulesOptions, FormElementTypes, FormInput, type FormInputElementProps, FormInputProps, FormItem, FormItemName, FormItemProps, type FormLabelElementProps, FormLang,
|
|
1490
|
+
export { BaseUrl, ErrorBoundary, ErrorBoundaryProps, ErrorChildrenProps, type FaasAction, type FaasActionUnionType, FaasBrowserClient, FaasBrowserClientAction, type FaasData, FaasDataInjection, FaasDataWrapper, FaasDataWrapperProps, FaasDataWrapperRef, type FaasParams, FaasReactClient, FaasReactClientInstance, FaasReactClientOptions, FormContainer as Form, type FormButtonElementProps, FormContextProps, FormContextProvider, FormDefaultElements, FormDefaultLang, FormDefaultRules, FormDefaultRulesOptions, FormElementTypes, FormInput, type FormInputElementProps, FormInputProps, FormItem, FormItemName, FormItemProps, type FormLabelElementProps, FormLang, FormProps, FormRule, FormRules, InferFormInputProps, InferFormRulesOptions, InferRuleOption, MockHandler, OnError, OptionalWrapper, OptionalWrapperProps, Options, Response, ResponseError, ResponseErrorProps, ResponseHeaders, ResponseProps, StateSetters, StatesWithSetters, UseFaasStreamOptions, UseFaasStreamResult, createSplittingContext, equal, faas, generateId, getClient, setMock, useConstant, useEqualCallback, useEqualEffect, useEqualMemo, useEqualMemoize, useFaas, useFaasOptions, useFaasStream, useFormContext, usePrevious, useSplittingState, useStateRef, validValues, withFaasData };
|
package/dist/index.mjs
CHANGED
|
@@ -38,7 +38,7 @@ function generateId(prefix = "", length = 18) {
|
|
|
38
38
|
* @param {ResponseProps<T>} [props] - Response properties including status, headers, body, and data.
|
|
39
39
|
* All properties are optional with sensible defaults.
|
|
40
40
|
*
|
|
41
|
-
*
|
|
41
|
+
* Notes:
|
|
42
42
|
* - status defaults to 200 if data or body is present, 204 otherwise
|
|
43
43
|
* - body is automatically populated from data if not explicitly provided
|
|
44
44
|
* - headers defaults to an empty object if not provided
|
|
@@ -156,7 +156,7 @@ var Response = class {
|
|
|
156
156
|
* including HTTP status code, response headers, response body, and the original error.
|
|
157
157
|
*
|
|
158
158
|
* @class ResponseError
|
|
159
|
-
* @
|
|
159
|
+
* @augments Error
|
|
160
160
|
*
|
|
161
161
|
* @property {number} status - The HTTP status code of the failed response. Defaults to 500 if not provided.
|
|
162
162
|
* @property {ResponseHeaders} headers - The response headers from the failed request.
|
|
@@ -237,7 +237,7 @@ var Response = class {
|
|
|
237
237
|
* })
|
|
238
238
|
* ```
|
|
239
239
|
*
|
|
240
|
-
*
|
|
240
|
+
* Notes:
|
|
241
241
|
* - ResponseError is automatically thrown by the action method when the server returns an error (status >= 400)
|
|
242
242
|
* - The error message from server responses is extracted from body.error.message if available
|
|
243
243
|
* - When created from an Error object, the original error is preserved in the originalError property
|
|
@@ -260,7 +260,7 @@ var ResponseError = class extends Error {
|
|
|
260
260
|
message: data,
|
|
261
261
|
...options
|
|
262
262
|
};
|
|
263
|
-
else if (data instanceof Error || data
|
|
263
|
+
else if (data instanceof Error || typeof data === "object" && data !== null && typeof data.constructor?.name === "string" && data.constructor.name.includes("Error")) props = {
|
|
264
264
|
message: data.message,
|
|
265
265
|
originalError: data,
|
|
266
266
|
...options
|
|
@@ -343,7 +343,7 @@ function setMock(handler) {
|
|
|
343
343
|
* - Streaming support for large responses
|
|
344
344
|
* - Multiple instance support with unique IDs
|
|
345
345
|
*
|
|
346
|
-
*
|
|
346
|
+
* Notes:
|
|
347
347
|
* - All requests are POST requests by default
|
|
348
348
|
* - Automatically adds X-FaasJS-Request-Id header for request tracking
|
|
349
349
|
* - baseUrl must end with '/' (will throw Error if not)
|
|
@@ -487,7 +487,7 @@ var FaasBrowserClient = class {
|
|
|
487
487
|
* @throws {ResponseError} When the server returns an error response (status >= 400 or body.error exists)
|
|
488
488
|
* @throws {NetworkError} When network request fails
|
|
489
489
|
*
|
|
490
|
-
*
|
|
490
|
+
* Notes:
|
|
491
491
|
* - All requests are POST requests by default
|
|
492
492
|
* - Action path is automatically converted to lowercase
|
|
493
493
|
* - A unique request ID is generated for each request and sent in X-FaasJS-Request-Id header
|
|
@@ -646,7 +646,7 @@ var FaasBrowserClient = class {
|
|
|
646
646
|
headers,
|
|
647
647
|
body
|
|
648
648
|
}));
|
|
649
|
-
} catch
|
|
649
|
+
} catch {
|
|
650
650
|
return Promise.reject(new ResponseError({
|
|
651
651
|
message: res,
|
|
652
652
|
status: response.status,
|
|
@@ -732,13 +732,18 @@ function equal(a, b) {
|
|
|
732
732
|
* @returns The memoized value.
|
|
733
733
|
*/
|
|
734
734
|
function useEqualMemoize(value) {
|
|
735
|
+
const ref = useRef(value);
|
|
736
|
+
if (!equal(value, ref.current)) ref.current = value;
|
|
737
|
+
return ref.current;
|
|
738
|
+
}
|
|
739
|
+
function useEqualSignal(value) {
|
|
735
740
|
const ref = useRef(value);
|
|
736
741
|
const signalRef = useRef(0);
|
|
737
742
|
if (!equal(value, ref.current)) {
|
|
738
743
|
ref.current = value;
|
|
739
744
|
signalRef.current += 1;
|
|
740
745
|
}
|
|
741
|
-
return
|
|
746
|
+
return signalRef.current;
|
|
742
747
|
}
|
|
743
748
|
/**
|
|
744
749
|
* Custom hook that works like `useEffect` but uses deep comparison on dependencies.
|
|
@@ -748,7 +753,7 @@ function useEqualMemoize(value) {
|
|
|
748
753
|
* @returns The result of the `useEffect` hook with memoized dependencies.
|
|
749
754
|
*/
|
|
750
755
|
function useEqualEffect(callback, dependencies) {
|
|
751
|
-
return useEffect(callback,
|
|
756
|
+
return useEffect(callback, [useEqualSignal(dependencies)]);
|
|
752
757
|
}
|
|
753
758
|
/**
|
|
754
759
|
* Custom hook that works like `useMemo` but uses deep comparison on dependencies.
|
|
@@ -758,7 +763,12 @@ function useEqualEffect(callback, dependencies) {
|
|
|
758
763
|
* @returns The result of the `useMemo` hook with memoized dependencies.
|
|
759
764
|
*/
|
|
760
765
|
function useEqualMemo(callback, dependencies) {
|
|
761
|
-
|
|
766
|
+
const signal = useEqualSignal(dependencies);
|
|
767
|
+
const callbackRef = useRef(callback);
|
|
768
|
+
callbackRef.current = callback;
|
|
769
|
+
return useMemo(() => {
|
|
770
|
+
return callbackRef.current();
|
|
771
|
+
}, [signal]);
|
|
762
772
|
}
|
|
763
773
|
/**
|
|
764
774
|
* Custom hook that works like `useCallback` but uses deep comparison on dependencies.
|
|
@@ -768,7 +778,7 @@ function useEqualMemo(callback, dependencies) {
|
|
|
768
778
|
* @returns The result of the `useCallback` hook with memoized dependencies.
|
|
769
779
|
*/
|
|
770
780
|
function useEqualCallback(callback, dependencies) {
|
|
771
|
-
return useCallback((...args) => callback(...args),
|
|
781
|
+
return useCallback((...args) => callback(...args), [useEqualSignal(dependencies)]);
|
|
772
782
|
}
|
|
773
783
|
const FaasDataWrapper = forwardRef((props, ref) => {
|
|
774
784
|
const requestOptions = {
|
|
@@ -867,7 +877,8 @@ function useFaas(action, defaultParams, options = {}) {
|
|
|
867
877
|
const nextData = r.data;
|
|
868
878
|
setFails(0);
|
|
869
879
|
setError(null);
|
|
870
|
-
options.setData
|
|
880
|
+
if (options.setData) options.setData(nextData);
|
|
881
|
+
else localSetData(nextData);
|
|
871
882
|
setLoading(false);
|
|
872
883
|
for (const { resolve } of pendingReloadsRef.current.values()) resolve(nextData);
|
|
873
884
|
pendingReloadsRef.current.clear();
|
|
@@ -1345,34 +1356,30 @@ async function validValues(rules, items, values, lang) {
|
|
|
1345
1356
|
//#region src/Form/Footer.tsx
|
|
1346
1357
|
function FormFooter() {
|
|
1347
1358
|
const { submitting, setSubmitting, onSubmit, valuesRef, Elements, items, setErrors, lang, rules } = useFormContext();
|
|
1348
|
-
const
|
|
1349
|
-
|
|
1350
|
-
setErrors({});
|
|
1351
|
-
const errors = await validValues(rules, items, valuesRef.current, lang);
|
|
1352
|
-
if (Object.keys(errors).length) {
|
|
1353
|
-
setErrors(errors);
|
|
1354
|
-
setSubmitting(false);
|
|
1355
|
-
return;
|
|
1356
|
-
}
|
|
1357
|
-
onSubmit(valuesRef.current).finally(() => setSubmitting(false));
|
|
1358
|
-
}, [
|
|
1359
|
-
setSubmitting,
|
|
1360
|
-
setErrors,
|
|
1361
|
-
rules,
|
|
1362
|
-
items,
|
|
1363
|
-
lang,
|
|
1364
|
-
onSubmit
|
|
1365
|
-
]);
|
|
1366
|
-
return useMemo(() => /* @__PURE__ */ jsx(Elements.Button, {
|
|
1359
|
+
const Button = Elements.Button;
|
|
1360
|
+
return /* @__PURE__ */ jsx(Button, {
|
|
1367
1361
|
submitting,
|
|
1368
|
-
submit:
|
|
1362
|
+
submit: useCallback(async () => {
|
|
1363
|
+
setSubmitting(true);
|
|
1364
|
+
setErrors({});
|
|
1365
|
+
const errors = await validValues(rules, items, valuesRef.current, lang);
|
|
1366
|
+
if (Object.keys(errors).length) {
|
|
1367
|
+
setErrors(errors);
|
|
1368
|
+
setSubmitting(false);
|
|
1369
|
+
return;
|
|
1370
|
+
}
|
|
1371
|
+
onSubmit(valuesRef.current).finally(() => setSubmitting(false));
|
|
1372
|
+
}, [
|
|
1373
|
+
setSubmitting,
|
|
1374
|
+
setErrors,
|
|
1375
|
+
rules,
|
|
1376
|
+
items,
|
|
1377
|
+
valuesRef,
|
|
1378
|
+
lang,
|
|
1379
|
+
onSubmit
|
|
1380
|
+
]),
|
|
1369
1381
|
children: lang.submit
|
|
1370
|
-
})
|
|
1371
|
-
submitting,
|
|
1372
|
-
handleSubmit,
|
|
1373
|
-
lang.submit,
|
|
1374
|
-
Elements.Button
|
|
1375
|
-
]);
|
|
1382
|
+
});
|
|
1376
1383
|
}
|
|
1377
1384
|
FormFooter.displayName = "FormFooter";
|
|
1378
1385
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faasjs/react",
|
|
3
|
-
"version": "8.0.0-beta.
|
|
3
|
+
"version": "8.0.0-beta.15",
|
|
4
4
|
"homepage": "https://faasjs.com/doc/react/",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"url": "https://github.com/faasjs/faasjs/issues"
|
|
@@ -26,16 +26,13 @@
|
|
|
26
26
|
"require": "./dist/index.cjs"
|
|
27
27
|
}
|
|
28
28
|
},
|
|
29
|
-
"scripts": {
|
|
30
|
-
"build": "tsdown src/index.ts --config ../../tsdown.config.ts --external react --dts.eager --no-sourcemap --no-dts.sourcemap"
|
|
31
|
-
},
|
|
32
29
|
"devDependencies": {
|
|
33
|
-
"@faasjs/types": ">=8.0.0-beta.
|
|
30
|
+
"@faasjs/types": ">=8.0.0-beta.15",
|
|
34
31
|
"@types/react": "^19.0.0",
|
|
35
32
|
"react": "^19.0.0"
|
|
36
33
|
},
|
|
37
34
|
"peerDependencies": {
|
|
38
|
-
"@faasjs/types": ">=8.0.0-beta.
|
|
35
|
+
"@faasjs/types": ">=8.0.0-beta.15"
|
|
39
36
|
},
|
|
40
37
|
"engines": {
|
|
41
38
|
"node": ">=24.0.0",
|