Skip to content

Commit

Permalink
refactor: remove additional fetchError prop from hook return object
Browse files Browse the repository at this point in the history
This commit removes the `fetchError` prop from hook return object. Now the returned object is of
type `SafeActionResult`. If an error gets thrown inside an action, and the `handleServerError` init
option rethrows it, now the `execute`/`executeAsync` functions throw it inside the component, so the
handling is up to the user.
  • Loading branch information
TheEdoRan committed Sep 7, 2024
1 parent 730d2c8 commit d8a3352
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 49 deletions.
10 changes: 5 additions & 5 deletions packages/next-safe-action/src/hooks-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import * as React from "react";
import {} from "react/experimental";
import type {} from "zod";
import type { InferIn, Schema } from "./adapters/types";
import type { HookActionStatus, HookBaseUtils, HookCallbacks, HookResult, HookShorthandStatus } from "./hooks.types";
import type { HookActionStatus, HookBaseUtils, HookCallbacks, HookShorthandStatus } from "./hooks.types";
import type { SafeActionResult } from "./index.types";

export const getActionStatus = <
ServerError,
Expand All @@ -18,7 +19,7 @@ export const getActionStatus = <
}: {
isIdle: boolean;
isExecuting: boolean;
result: HookResult<ServerError, S, BAS, CVE, CBAVE, Data>;
result: SafeActionResult<ServerError, S, BAS, CVE, CBAVE, Data>;
}): HookActionStatus => {
if (isIdle) {
return "idle";
Expand All @@ -27,8 +28,7 @@ export const getActionStatus = <
} else if (
typeof result.validationErrors !== "undefined" ||
typeof result.bindArgsValidationErrors !== "undefined" ||
typeof result.serverError !== "undefined" ||
typeof result.fetchError !== "undefined"
typeof result.serverError !== "undefined"
) {
return "hasErrored";
} else {
Expand Down Expand Up @@ -87,7 +87,7 @@ export const useActionCallbacks = <
status,
cb,
}: {
result: HookResult<ServerError, S, BAS, CVE, CBAVE, Data>;
result: SafeActionResult<ServerError, S, BAS, CVE, CBAVE, Data>;
input: S extends Schema ? InferIn<S> : undefined;
status: HookActionStatus;
cb?: HookCallbacks<ServerError, S, BAS, CVE, CBAVE, Data>;
Expand Down
31 changes: 5 additions & 26 deletions packages/next-safe-action/src/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
"use client";

import { isNotFoundError } from "next/dist/client/components/not-found.js";
import { isRedirectError } from "next/dist/client/components/redirect.js";
import * as React from "react";
import {} from "react/experimental";
import type {} from "zod";
Expand All @@ -10,12 +8,11 @@ import { getActionShorthandStatusObject, getActionStatus, useActionCallbacks, us
import type {
HookBaseUtils,
HookCallbacks,
HookResult,
HookSafeActionFn,
UseActionHookReturn,
UseOptimisticActionHookReturn,
} from "./hooks.types";
import { isError } from "./utils";
import type { SafeActionResult } from "./index.types";

// HOOKS

Expand All @@ -38,7 +35,7 @@ export const useAction = <
utils?: HookBaseUtils<S> & HookCallbacks<ServerError, S, BAS, CVE, CBAVE, Data>
): UseActionHookReturn<ServerError, S, BAS, CVE, CBAVE, Data> => {
const [isTransitioning, startTransition] = React.useTransition();
const [result, setResult] = React.useState<HookResult<ServerError, S, BAS, CVE, CBAVE, Data>>({});
const [result, setResult] = React.useState<SafeActionResult<ServerError, S, BAS, CVE, CBAVE, Data>>({});
const [clientInput, setClientInput] = React.useState<S extends Schema ? InferIn<S> : void>();
const [isExecuting, setIsExecuting] = React.useState(false);
const [isIdle, setIsIdle] = React.useState(true);
Expand All @@ -57,11 +54,7 @@ export const useAction = <
safeActionFn(input as S extends Schema ? InferIn<S> : undefined)
.then((res) => setResult(res ?? {}))
.catch((e) => {
if (isRedirectError(e) || isNotFoundError(e)) {
throw e;
}

setResult({ fetchError: isError(e) ? e.message : "Something went wrong" });
throw e;
})
.finally(() => {
setIsExecuting(false);
Expand All @@ -87,11 +80,6 @@ export const useAction = <
resolve(res);
})
.catch((e) => {
if (isRedirectError(e) || isNotFoundError(e)) {
throw e;
}

setResult({ fetchError: isError(e) ? e.message : "Something went wrong" });
reject(e);
})
.finally(() => {
Expand Down Expand Up @@ -163,7 +151,7 @@ export const useOptimisticAction = <
HookCallbacks<ServerError, S, BAS, CVE, CBAVE, Data>
): UseOptimisticActionHookReturn<ServerError, S, BAS, CVE, CBAVE, Data, State> => {
const [isTransitioning, startTransition] = React.useTransition();
const [result, setResult] = React.useState<HookResult<ServerError, S, BAS, CVE, CBAVE, Data>>({});
const [result, setResult] = React.useState<SafeActionResult<ServerError, S, BAS, CVE, CBAVE, Data>>({});
const [clientInput, setClientInput] = React.useState<S extends Schema ? InferIn<S> : void>();
const [isExecuting, setIsExecuting] = React.useState(false);
const [isIdle, setIsIdle] = React.useState(true);
Expand All @@ -187,11 +175,7 @@ export const useOptimisticAction = <
safeActionFn(input as S extends Schema ? InferIn<S> : undefined)
.then((res) => setResult(res ?? {}))
.catch((e) => {
if (isRedirectError(e) || isNotFoundError(e)) {
throw e;
}

setResult({ fetchError: isError(e) ? e.message : "Something went wrong" });
throw e;
})
.finally(() => {
setIsExecuting(false);
Expand All @@ -218,11 +202,6 @@ export const useOptimisticAction = <
resolve(res);
})
.catch((e) => {
if (isRedirectError(e) || isNotFoundError(e)) {
throw e;
}

setResult({ fetchError: isError(e) ? e.message : "Something went wrong" });
reject(e);
})
.finally(() => {
Expand Down
21 changes: 3 additions & 18 deletions packages/next-safe-action/src/hooks.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,6 @@ export type HookBaseUtils<S extends Schema | undefined> = {
}) & { delayMs?: number };
};

/**
* Type of `result` object returned by `useAction`, `useOptimisticAction` and `useStateAction` hooks.
* If a server-client communication error occurs, `fetchError` will be set to the error message.
*/
export type HookResult<
ServerError,
S extends Schema | undefined,
BAS extends readonly Schema[],
CVE,
CBAVE,
Data,
> = SafeActionResult<ServerError, S, BAS, CVE, CBAVE, Data> & {
fetchError?: string;
};

/**
* Type of hooks callbacks. These are executed when action is in a specific state.
*/
Expand All @@ -42,11 +27,11 @@ export type HookCallbacks<
onExecute?: (args: { input: S extends Schema ? InferIn<S> : undefined }) => MaybePromise<void>;
onSuccess?: (args: { data?: Data; input: S extends Schema ? InferIn<S> : undefined }) => MaybePromise<void>;
onError?: (args: {
error: Prettify<Omit<HookResult<ServerError, S, BAS, CVE, CBAVE, Data>, "data">>;
error: Prettify<Omit<SafeActionResult<ServerError, S, BAS, CVE, CBAVE, Data>, "data">>;
input: S extends Schema ? InferIn<S> : undefined;
}) => MaybePromise<void>;
onSettled?: (args: {
result: Prettify<HookResult<ServerError, S, BAS, CVE, CBAVE, Data>>;
result: Prettify<SafeActionResult<ServerError, S, BAS, CVE, CBAVE, Data>>;
input: S extends Schema ? InferIn<S> : undefined;
}) => MaybePromise<void>;
};
Expand Down Expand Up @@ -115,7 +100,7 @@ export type UseActionHookReturn<
input: S extends Schema ? InferIn<S> : void
) => Promise<SafeActionResult<ServerError, S, BAS, CVE, CBAVE, Data> | undefined>;
input: S extends Schema ? InferIn<S> : undefined;
result: Prettify<HookResult<ServerError, S, BAS, CVE, CBAVE, Data>>;
result: Prettify<SafeActionResult<ServerError, S, BAS, CVE, CBAVE, Data>>;
reset: () => void;
status: HookActionStatus;
} & HookShorthandStatus;
Expand Down

0 comments on commit d8a3352

Please sign in to comment.