Skip to content

Commit e33216e

Browse files
committed
Use FormData submitter parameter
1 parent 149b917 commit e33216e

File tree

6 files changed

+27
-77
lines changed

6 files changed

+27
-77
lines changed

packages/react-dom-bindings/src/events/plugins/FormActionEventPlugin.js

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -45,30 +45,6 @@ function coerceFormActionProp(
4545
}
4646
}
4747

48-
function createFormDataWithSubmitter(
49-
form: HTMLFormElement,
50-
submitter: HTMLInputElement | HTMLButtonElement,
51-
) {
52-
// The submitter's value should be included in the FormData.
53-
// It should be in the document order in the form.
54-
// Since the FormData constructor invokes the formdata event it also
55-
// needs to be available before that happens so after construction it's too
56-
// late. We use a temporary fake node for the duration of this event.
57-
// TODO: FormData takes a second argument that it's the submitter but this
58-
// is fairly new so not all browsers support it yet. Switch to that technique
59-
// when available.
60-
const temp = submitter.ownerDocument.createElement('input');
61-
temp.name = submitter.name;
62-
temp.value = submitter.value;
63-
if (form.id) {
64-
temp.setAttribute('form', form.id);
65-
}
66-
(submitter.parentNode: any).insertBefore(temp, submitter);
67-
const formData = new FormData(form);
68-
(temp.parentNode: any).removeChild(temp);
69-
return formData;
70-
}
71-
7248
/**
7349
* This plugin invokes action functions on forms, inputs and buttons if
7450
* the form doesn't prevent default.
@@ -129,9 +105,8 @@ function extractEvents(
129105
if (didCurrentEventScheduleTransition()) {
130106
// We're going to set the pending form status, but because the submission
131107
// was prevented, we should not fire the action function.
132-
const formData = submitter
133-
? createFormDataWithSubmitter(form, submitter)
134-
: new FormData(form);
108+
// $FlowExpectedError[extra-arg]: flow doesn't know about the 'submitter' parameter yet
109+
const formData = new FormData(form, submitter);
135110
const pendingState: FormStatus = {
136111
pending: true,
137112
data: formData,
@@ -160,9 +135,8 @@ function extractEvents(
160135
event.preventDefault();
161136

162137
// Dispatch the action and set a pending form status.
163-
const formData = submitter
164-
? createFormDataWithSubmitter(form, submitter)
165-
: new FormData(form);
138+
// $FlowExpectedError[extra-arg]: flow doesn't know about the 'submitter' parameter yet
139+
const formData = new FormData(form, submitter);
166140
const pendingState: FormStatus = {
167141
pending: true,
168142
data: formData,

packages/react-dom-bindings/src/server/fizz-instruction-set/ReactDOMFizzInstructionSetInlineCodeStrings.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/react-dom-bindings/src/server/fizz-instruction-set/ReactDOMFizzInstructionSetShared.js

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -172,25 +172,7 @@ export function listenToFormSubmissionsForReplaying() {
172172
event.preventDefault();
173173

174174
// Take a snapshot of the FormData at the time of the event.
175-
let formData;
176-
if (formDataSubmitter) {
177-
// The submitter's value should be included in the FormData.
178-
// It should be in the document order in the form.
179-
// Since the FormData constructor invokes the formdata event it also
180-
// needs to be available before that happens so after construction it's too
181-
// late. We use a temporary fake node for the duration of this event.
182-
// TODO: FormData takes a second argument that it's the submitter but this
183-
// is fairly new so not all browsers support it yet. Switch to that technique
184-
// when available.
185-
const temp = document.createElement('input');
186-
temp.name = formDataSubmitter.name;
187-
temp.value = formDataSubmitter.value;
188-
formDataSubmitter.parentNode.insertBefore(temp, formDataSubmitter);
189-
formData = new FormData(form);
190-
temp.parentNode.removeChild(temp);
191-
} else {
192-
formData = new FormData(form);
193-
}
175+
const formData = new FormData(form, formDataSubmitter);
194176

195177
// Queue for replaying later. This field could potentially be shared with multiple
196178
// Reacts on the same page since each one will preventDefault for the next one.

packages/react-dom/src/__tests__/ReactDOMForm-test.js

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ global.IS_REACT_ACT_ENVIRONMENT = true;
1414
// Our current version of JSDOM doesn't implement the event dispatching
1515
// so we polyfill it.
1616
const NativeFormData = global.FormData;
17-
const FormDataPolyfill = function FormData(form) {
18-
const formData = new NativeFormData(form);
17+
const FormDataPolyfill = function FormData(form, submitter) {
18+
const formData = new NativeFormData(form, submitter);
1919
const formDataEvent = new Event('formdata', {
2020
bubbles: true,
2121
cancelable: false,
@@ -487,11 +487,16 @@ describe('ReactDOMForm', () => {
487487
const inputRef = React.createRef();
488488
const buttonRef = React.createRef();
489489
const outsideButtonRef = React.createRef();
490+
const imageButtonRef = React.createRef();
490491
let button;
492+
let buttonX;
493+
let buttonY;
491494
let title;
492495

493496
function action(formData) {
494497
button = formData.get('button');
498+
buttonX = formData.get('button.x');
499+
buttonY = formData.get('button.y');
495500
title = formData.get('title');
496501
}
497502

@@ -506,6 +511,12 @@ describe('ReactDOMForm', () => {
506511
<button name="button" value="edit" ref={buttonRef}>
507512
Edit
508513
</button>
514+
<input
515+
type="image"
516+
name="button"
517+
href="/some/image.png"
518+
ref={imageButtonRef}
519+
/>
509520
</form>
510521
<form id="form" action={action}>
511522
<input type="text" name="title" defaultValue="hello" />
@@ -544,9 +555,12 @@ describe('ReactDOMForm', () => {
544555
expect(button).toBe('outside');
545556
expect(title).toBe('hello');
546557

547-
// Ensure that the type field got correctly restored
548-
expect(inputRef.current.getAttribute('type')).toBe('submit');
549-
expect(buttonRef.current.getAttribute('type')).toBe(null);
558+
await submit(imageButtonRef.current);
559+
560+
expect(button).toBe(null);
561+
expect(buttonX).toBe('0');
562+
expect(buttonY).toBe('0');
563+
expect(title).toBe('hello');
550564
});
551565

552566
it('excludes the submitter name when the submitter is a function action', async () => {

packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMForm-test.js

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -79,17 +79,7 @@ describe('ReactFlightDOMForm', () => {
7979
const method = (submitter && submitter.formMethod) || form.method;
8080
const encType = (submitter && submitter.formEnctype) || form.enctype;
8181
if (method === 'post' && encType === 'multipart/form-data') {
82-
let formData;
83-
if (submitter) {
84-
const temp = document.createElement('input');
85-
temp.name = submitter.name;
86-
temp.value = submitter.value;
87-
submitter.parentNode.insertBefore(temp, submitter);
88-
formData = new FormData(form);
89-
temp.parentNode.removeChild(temp);
90-
} else {
91-
formData = new FormData(form);
92-
}
82+
const formData = new FormData(form, submitter);
9383
return POST(formData);
9484
}
9585
throw new Error('Navigate to: ' + action);

packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMForm-test.js

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -118,17 +118,7 @@ describe('ReactFlightDOMForm', () => {
118118
const method = (submitter && submitter.formMethod) || form.method;
119119
const encType = (submitter && submitter.formEnctype) || form.enctype;
120120
if (method === 'post' && encType === 'multipart/form-data') {
121-
let formData;
122-
if (submitter) {
123-
const temp = document.createElement('input');
124-
temp.name = submitter.name;
125-
temp.value = submitter.value;
126-
submitter.parentNode.insertBefore(temp, submitter);
127-
formData = new FormData(form);
128-
temp.parentNode.removeChild(temp);
129-
} else {
130-
formData = new FormData(form);
131-
}
121+
const formData = new FormData(form, submitter);
132122
return POST(formData);
133123
}
134124
throw new Error('Navigate to: ' + action);

0 commit comments

Comments
 (0)