Skip to content

Commit

Permalink
refactor: pull huge onSubmit callback out
Browse files Browse the repository at this point in the history
  • Loading branch information
lubieowoce committed Jul 24, 2024
1 parent f483a74 commit 56ee747
Showing 1 changed file with 84 additions and 60 deletions.
144 changes: 84 additions & 60 deletions packages/next/src/client/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,87 +45,111 @@ export default function Form({ replace, ...props }: FormProps) {

const actionHref = addBasePath(actionProp)

const onSubmit = (event: FormEvent<HTMLFormElement>) => {
if (typeof props.onSubmit === 'function') {
const { onSubmit: onSubmitProp } = props
onSubmitProp(event)

// if the user called event.preventDefault(), do nothing.
// (this matches what Link does for `onClick`)
if (event.defaultPrevented) {
return
return (
<form
{...props}
action={actionHref}
onSubmit={(event) =>
onFormSubmit(event, {
router,
actionHref,
replace,
onSubmit: props.onSubmit,
})
}
}
/>
)
}

const formElement = event.currentTarget
const submitter = (event.nativeEvent as SubmitEvent).submitter
const onFormSubmit = (
event: FormEvent<HTMLFormElement>,
{
actionHref,
onSubmit,
replace,
router,
}: {
actionHref: string
onSubmit: FormProps['onSubmit']
replace: FormProps['replace']
router: any
}
) => {
if (typeof onSubmit === 'function') {
onSubmit(event)

// if the user called event.preventDefault(), do nothing.
// (this matches what Link does for `onClick`)
if (event.defaultPrevented) {
return
}
}

let action = actionHref
const formElement = event.currentTarget
const submitter = (event.nativeEvent as SubmitEvent).submitter

if (submitter) {
if (process.env.NODE_ENV === 'development') {
// the way server actions are encoded (e.g. `formMethod="post")
// causes some unnecessary dev-mode warnings from `hasUnsupportedSubmitterAttributes`.
// we'd bail out anyway, but we just do it silently.
if (hasReactServerActionAttributes(submitter)) {
return
}
}
let action = actionHref

if (hasUnsupportedSubmitterAttributes(submitter)) {
if (submitter) {
if (process.env.NODE_ENV === 'development') {
// the way server actions are encoded (e.g. `formMethod="post")
// causes some unnecessary dev-mode warnings from `hasUnsupportedSubmitterAttributes`.
// we'd bail out anyway, but we just do it silently.
if (hasReactServerActionAttributes(submitter)) {
return
}
}

// client actions have `formAction="javascript:..."`. We obviously can't prefetch/navigate to that.
if (hasReactClientActionAttributes(submitter)) {
return
}
if (hasUnsupportedSubmitterAttributes(submitter)) {
return
}

// If the submitter specified an alternate formAction,
// use that URL instead -- this is what a native form would do.
// NOTE: `submitter.formAction` is unreliable, because it will give us `location.href` if it *wasn't* set
// NOTE: this should not have `basePath` added, because we can't add it before hydration
const submitterFormAction = submitter.getAttribute('formAction')
if (submitterFormAction !== null) {
action = submitterFormAction
}
// client actions have `formAction="javascript:..."`. We obviously can't prefetch/navigate to that.
if (hasReactClientActionAttributes(submitter)) {
return
}

// TODO: is it a problem that we've got an absolute URL here?
const targetUrl = new URL(action, document.baseURI)
if (targetUrl.searchParams.size) {
// url-encoded HTML forms ignore any queryparams in the `action` url. We need to match that.
// (note that all other parts of the URL, like `hash`, are preserved)
targetUrl.search = ''
// If the submitter specified an alternate formAction,
// use that URL instead -- this is what a native form would do.
// NOTE: `submitter.formAction` is unreliable, because it will give us `location.href` if it *wasn't* set
// NOTE: this should not have `basePath` added, because we can't add it before hydration
const submitterFormAction = submitter.getAttribute('formAction')
if (submitterFormAction !== null) {
action = submitterFormAction
}
}

const formData = new FormData(formElement)
// TODO: is it a problem that we've got an absolute URL here?
const targetUrl = new URL(action, document.baseURI)
if (targetUrl.searchParams.size) {
// url-encoded HTML forms ignore any queryparams in the `action` url. We need to match that.
// (note that all other parts of the URL, like `hash`, are preserved)
targetUrl.search = ''
}

for (const [name, value] of formData) {
if (typeof value !== 'string') {
// if it's not a string, then it was a file input.
// we can't do anything with those.
if (process.env.NODE_ENV === 'development') {
console.error(
'next/form does not support file inputs. Use a native <form> instead.'
)
}
const formData = new FormData(formElement)

return
for (const [name, value] of formData) {
if (typeof value !== 'string') {
// if it's not a string, then it was a file input.
// we can't do anything with those.
if (process.env.NODE_ENV === 'development') {
console.error(
'next/form does not support file inputs. Use a native <form> instead.'
)
}

targetUrl.searchParams.append(name, value)
return
}

// Finally, no more reasons for bailing out.
event.preventDefault()

const method = replace ? 'replace' : 'push'

router[method](targetUrl.href)
targetUrl.searchParams.append(name, value)
}

return <form {...props} action={actionHref} onSubmit={onSubmit} />
// Finally, no more reasons for bailing out.
event.preventDefault()

const method = replace ? 'replace' : 'push'
router[method](targetUrl.href)
}

const isSupportedEncType = (value: string) =>
Expand Down

0 comments on commit 56ee747

Please sign in to comment.