Add sumbitAction helper
This commit is contained in:
parent
eb4a1fac14
commit
c9cec8363b
|
|
@ -46,6 +46,43 @@ export const useAction = <TAction extends Action>() => {
|
|||
return { data, loading: status === "submitting", error }
|
||||
}
|
||||
|
||||
// Helper to submit an action without a form
|
||||
type SubmitActionOptions = {
|
||||
url?: string
|
||||
method?: "POST" | "PUT" | "PATCH" | "DELETE"
|
||||
}
|
||||
export const submitAction = async (data: any, options: SubmitActionOptions = {}) => {
|
||||
const actionFns = window._actionFns
|
||||
|
||||
try {
|
||||
const { url = window.location.href, method = "POST" } = options
|
||||
|
||||
actionFns?.setStatus("submitting")
|
||||
|
||||
const body = new FormData()
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
body.append(key, String(value))
|
||||
})
|
||||
|
||||
const res = await fetch(url, { method, body })
|
||||
|
||||
if (res.ok) {
|
||||
const { actionData, loaderData } = (await res.json()) as any
|
||||
window._setLoaderData!(loaderData)
|
||||
|
||||
actionFns?.setData(actionData)
|
||||
} else {
|
||||
const errorText = await res.text()
|
||||
throw new Error(`Error ${res.status}: ${errorText}`)
|
||||
}
|
||||
} catch (error) {
|
||||
actionFns?.setError(`${error}`)
|
||||
console.log(`🚨 Failed to submit`, error)
|
||||
} finally {
|
||||
actionFns?.setStatus("idle")
|
||||
}
|
||||
}
|
||||
|
||||
// Form component with built-in enhancement
|
||||
type FormProps = JSX.IntrinsicElements["form"] & { name: string }
|
||||
export const Form = (props: FormProps) => {
|
||||
|
|
@ -62,11 +99,8 @@ export const Form = (props: FormProps) => {
|
|||
const form = e.currentTarget as HTMLFormElement
|
||||
const body = new FormData(form)
|
||||
body.append("_actionName", props.name)
|
||||
const res = await fetch(form.action || window.location.href, {
|
||||
method: props.method || "POST",
|
||||
body,
|
||||
headers: { Accept: "application/json" },
|
||||
})
|
||||
const url = form.action || window.location.href
|
||||
const res = await fetch(url, { method: props.method || "POST", body })
|
||||
|
||||
if (res.status === 303) {
|
||||
window.location.href = res.headers.get("Location")!
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
import { nanoRemix } from "@/nanoRemix"
|
||||
import { Form, useAction, wrapComponentWithLoader } from "@/clientHelpers"
|
||||
|
||||
export { Form, useAction, wrapComponentWithLoader }
|
||||
export { nanoRemix }
|
||||
export { Form, useAction, wrapComponentWithLoader, submitAction } from "@/clientHelpers"
|
||||
export { nanoRemix } from "@/nanoRemix"
|
||||
|
||||
export type Loader<Data extends object> = (
|
||||
req: Request,
|
||||
|
|
|
|||
|
|
@ -21,8 +21,6 @@ export const nanoRemix = async (req: Request, options: Options = {}) => {
|
|||
const basename = ext ? url.pathname.slice(0, -ext.length) : url.pathname
|
||||
const route = router.match(basename)
|
||||
|
||||
console.log(`🌭 requesting ${url} got ${route?.pathname}`)
|
||||
|
||||
if (!route) {
|
||||
return new Response("Route Not Found", {
|
||||
status: 404,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import type { Action, Loader } from "@/main"
|
||||
export const renderServer = async (req: Request, route: Bun.MatchedRoute) => {
|
||||
const accept = req.headers.get("Accept")
|
||||
const contentType = req.headers.get("Content-Type")
|
||||
|
||||
if (accept === "application/json") {
|
||||
if (contentType?.startsWith("multipart/form-data;")) {
|
||||
return await handleAction(req, route)
|
||||
} else {
|
||||
return await renderHtml(req, route)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user