Skip to main content
Version: 3.x.x

useSubmit


Introduction

This hook mutates data on the server and supports controlling requests. It uses the Submit Dispatcher to handle requests and the Cache to manage the overall state of the data.

The minimum requirement for useSubmit is a prepared Request.

If you intend to retrieve data from the server, we recommend choosing the useFetch hook.


Initialization

const { submit, submitting, onSubmitSuccess, onSubmitError, onSubmitFinished } = useSubmit(postLogin);

How it works?

useSubmit executes a request when a submit() function returned from it gets triggered. It uses dependency tracking to limit re-rendering and improve performance. Under the hood, communication with the core systems is established by event emitters. Many "helper hooks" (such as onSubmitSuccess, onSubmitError, onSubmitFinished, etc.) are returned; these will help handle the request flow and lifecycle. This approach avoids overloading the base hook with callback logic. It also helps improve code readability, decreases code complication, and promotes more organized code.

import { useSubmit } from "@hyper-fetch/react";
import { postLogin } from "server";

interface Values {
email: string;
password: string;
}

const LoginPage: React.FC = () => {
const { submit, submitting, onSubmitSuccess, onSubmitError, onSubmitFinished } = useSubmit(postLogin);

onSubmitSuccess(({ response }) => {
console.log(response); // { token: string, refreshToken: string }
});

onSubmitError(({ response }) => {
console.log(response); // { message: string }
});

onSubmitFinished(({ response }) => {
const [payload, error, status] = response;
console.log(payload); // { token: string, refreshToken: string } | null
console.log(error); // { message: string } | null
console.log(status); // 200 / 400 / 404 / 500 ...
});

const onSubmit = (values: Values) => {
submit({ data: values });
};

return (
<Formik initialValues={initialValues} onSubmit={onSubmit} validationSchema={validationSchema}>
<Form>
{error && <Alert severity="error">{error.error_message}</Alert>}
<FormInput name="email" label="Email" placeholder="Fill your email" />
<FormInput type="password" name="password" label="Password" placeholder="Fill your password" />
<Button type="submit" variant="contained" disabled={submitting} className={styles.submit}>
Log in
</Button>
</Form>
</Formik>
);
};

Passing data and params

Data and parameters can be passed in several ways. One option is to use methods on the Request, such as setData or setParams.

const { submit } = useSubmit(patchUser.setParams({ userId: 1 }).setData({ name: "New Name" }));

However, you may need to pass parameters dynamically, which requires using submit function options.

const { submit } = useSubmit(patchUser);

const handleSubmit = (id: number, name: string) => {
submit({ data: { name }, params: { userId: id }, queryParams: { search: "test" } });
};

Options

These configuration options should be provided as a second parameter:

const { ... } = useSubmit(request, options)

{
bounce: boolean;
deepCompare: boolean | typeof isEqual;
dependencyTracking: boolean;
disabled: boolean;
initialData: {
...params1: ResponseReturnType<Response, Error, AdapterType>;
...params2: ResponseDetailsType;
cacheTime: number;
clearKey: string;
garbageCollection: number;
}[data] | null;
...params2: {bounceTime:number,bounceType:debounce} | {bounceTime:number,bounceTimeout:number,bounceType:throttle};
}


Returns

Returned values from this hook:

const values = useSubmit(request);

{
additionalData: T extends BaseAdapterType<any, any, any, infer A, any> ? A : never;
data: null | T extends Request<infer D, any, any, any, any, any, any, any, any, any> ? D : never;
error: null | T extends Request<any, any, any, infer G, infer L, any, any, any, any, any> ? G | L : never;
isSuccess: boolean;
retries: number;
status: T extends BaseAdapterType<any, any, infer S, any, any> ? S : never;
timestamp: null | Date;
setAdditionalData: (additionalData: ExtractAdapterAdditionalDataType<ExtractAdapterType<T>>, emitToCache?: boolean) => void;
setData: (data: ExtractResponseType<T>, emitToCache?: boolean) => void;
setError: (error: ExtractErrorType<T>, emitToCache?: boolean) => void;
setIsSuccess: (isSuccess: boolean, emitToCache?: boolean) => void;
setLoading: (loading: boolean, emitToHooks?: boolean) => void;
setRetries: (retries: number, emitToCache?: boolean) => void;
setStatus: (status: ExtractAdapterStatusType<ExtractAdapterType<T>>, emitToCache?: boolean) => void;
setTimestamp: (timestamp: Date, emitToCache?: boolean) => void;
abort: () => void;
bounce: {
active: boolean;
reset: () => void;
};
onSubmitAbort: (callback: OnErrorCallbackType<RequestType>) => void;
onSubmitDownloadProgress: (callback: OnProgressCallbackType) => void;
onSubmitError: (callback: OnErrorCallbackType<RequestType>) => void;
onSubmitFinished: (callback: OnFinishedCallbackType<RequestType>) => void;
onSubmitOfflineError: (callback: OnErrorCallbackType<RequestType>) => void;
onSubmitRequestStart: (callback: OnStartCallbackType<RequestType>) => void;
onSubmitResponseStart: (callback: OnStartCallbackType<RequestType>) => void;
onSubmitSuccess: (callback: OnSuccessCallbackType<RequestType>) => void;
onSubmitUploadProgress: (callback: OnProgressCallbackType) => void;
revalidate: (invalidateKey: InvalidationKeyType | InvalidationKeyType[]) => void;
submit: RequestSendOptionsType<Request>[data] extends NegativeTypes ? (RequestSendOptionsType<Request>[params] extends NegativeTypes ? (options?: RequestSendOptionsType<Request>) => Promise<ResponseReturnType<ExtractResponseType<Request>, ExtractErrorType<Request>, ExtractAdapterType<Request>>> : (options: RequestSendOptionsType<Request>) => Promise<ResponseReturnType<ExtractResponseType<Request>, ExtractErrorType<Request>, ExtractAdapterType<Request>>>) : (options: RequestSendOptionsType<Request>) => Promise<ResponseReturnType<ExtractResponseType<Request>, ExtractErrorType<Request>, ExtractAdapterType<Request>>>;
submitting: boolean;
}