Skip to content

Instantly share code, notes, and snippets.

@kiliman
Created February 7, 2023 21:31
Show Gist options
  • Select an option

  • Save kiliman/c900df084ea7dd306e0cb85b81848fbb to your computer and use it in GitHub Desktop.

Select an option

Save kiliman/c900df084ea7dd306e0cb85b81848fbb to your computer and use it in GitHub Desktop.
Remix `useSubmitPromise` hook
import type { ActionArgs, LoaderArgs } from "@remix-run/node";
import { json } from "@remix-run/node";
import type { SubmitOptions } from "@remix-run/react";
import { useActionData, useNavigation, useSubmit } from "@remix-run/react";
import { useCallback, useEffect, useMemo } from "react";
export function loader({ request }: LoaderArgs) {
return json({ message: "Hello World" });
}
export function action({ request }: ActionArgs) {
return json({ message: "Goodbye World" });
}
export default function Index() {
const submit = useSubmitPromise();
const doSubmit = useCallback(
(e: any) => {
console.log("doSubmit");
e.preventDefault();
submit({ test: "123" }, { method: "post", action: "?index" }).then(
(data) => {
console.log("result", data);
}
);
},
[submit]
);
return (
<div>
<h1>Welcome to Remix</h1>
<button onClick={doSubmit}>useSubmitPromise</button>
</div>
);
}
// remix doesn't export this type
declare type SubmitTarget =
| HTMLFormElement
| HTMLButtonElement
| HTMLInputElement
| FormData
| URLSearchParams
| {
[name: string]: string;
}
| null;
function useSubmitPromise() {
const submit = useSubmit();
const navigation = useNavigation();
const actionData = useActionData();
const $deferred = useMemo(() => deferred(), []);
useEffect(() => {
if (navigation.state === "idle" && actionData) {
$deferred.resolve(actionData);
}
}, [$deferred, navigation.state, actionData]);
const _submit = useCallback(
(target: SubmitTarget, options: SubmitOptions = {}) => {
submit(target, options);
return $deferred.promise;
},
[$deferred.promise, submit]
);
return _submit;
}
// create a *deferred* promise
function deferred() {
let resolve: any;
let reject: any;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
return { resolve, reject, promise };
}
@kiliman

kiliman commented Feb 7, 2023

Copy link
Copy Markdown
Author

Sample app on ⚡️StackBlitz
https://stackblitz.com/edit/node-crfv2p

@yaoweiprc

Copy link
Copy Markdown

It seems that you use the same promise instance every time which means that it's status can not be changed once it's settled. You can only use _submit().then() once.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment