Skip to content

Commit 65eec42

Browse files
authored
Use FormData submitter parameter (facebook#29028)
1 parent 454fc41 commit 65eec42

File tree

5 files changed

+24
-66
lines changed

5 files changed

+24
-66
lines changed

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

Lines changed: 2 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,7 @@ 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+
const formData = new FormData(form, submitter);
135109
const pendingState: FormStatus = {
136110
pending: true,
137111
data: formData,
@@ -160,9 +134,7 @@ function extractEvents(
160134
event.preventDefault();
161135

162136
// Dispatch the action and set a pending form status.
163-
const formData = submitter
164-
? createFormDataWithSubmitter(form, submitter)
165-
: new FormData(form);
137+
const formData = new FormData(form, submitter);
166138
const pendingState: FormStatus = {
167139
pending: true,
168140
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
@@ -634,25 +634,7 @@ export function listenToFormSubmissionsForReplaying() {
634634
event.preventDefault();
635635

636636
// Take a snapshot of the FormData at the time of the event.
637-
let formData;
638-
if (formDataSubmitter) {
639-
// The submitter's value should be included in the FormData.
640-
// It should be in the document order in the form.
641-
// Since the FormData constructor invokes the formdata event it also
642-
// needs to be available before that happens so after construction it's too
643-
// late. We use a temporary fake node for the duration of this event.
644-
// TODO: FormData takes a second argument that it's the submitter but this
645-
// is fairly new so not all browsers support it yet. Switch to that technique
646-
// when available.
647-
const temp = document.createElement('input');
648-
temp.name = formDataSubmitter.name;
649-
temp.value = formDataSubmitter.value;
650-
formDataSubmitter.parentNode.insertBefore(temp, formDataSubmitter);
651-
formData = new FormData(form);
652-
temp.parentNode.removeChild(temp);
653-
} else {
654-
formData = new FormData(form);
655-
}
637+
const formData = new FormData(form, formDataSubmitter);
656638

657639
// Queue for replaying later. This field could potentially be shared with multiple
658640
// 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,
@@ -489,11 +489,16 @@ describe('ReactDOMForm', () => {
489489
const inputRef = React.createRef();
490490
const buttonRef = React.createRef();
491491
const outsideButtonRef = React.createRef();
492+
const imageButtonRef = React.createRef();
492493
let button;
494+
let buttonX;
495+
let buttonY;
493496
let title;
494497

495498
function action(formData) {
496499
button = formData.get('button');
500+
buttonX = formData.get('button.x');
501+
buttonY = formData.get('button.y');
497502
title = formData.get('title');
498503
}
499504

@@ -508,6 +513,12 @@ describe('ReactDOMForm', () => {
508513
<button name="button" value="edit" ref={buttonRef}>
509514
Edit
510515
</button>
516+
<input
517+
type="image"
518+
name="button"
519+
href="/some/image.png"
520+
ref={imageButtonRef}
521+
/>
511522
</form>
512523
<form id="form" action={action}>
513524
<input type="text" name="title" defaultValue="hello" />
@@ -546,9 +557,12 @@ describe('ReactDOMForm', () => {
546557
expect(button).toBe('outside');
547558
expect(title).toBe('hello');
548559

549-
// Ensure that the type field got correctly restored
550-
expect(inputRef.current.getAttribute('type')).toBe('submit');
551-
expect(buttonRef.current.getAttribute('type')).toBe(null);
560+
await submit(imageButtonRef.current);
561+
562+
expect(button).toBe(null);
563+
expect(buttonX).toBe('0');
564+
expect(buttonY).toBe('0');
565+
expect(title).toBe('hello');
552566
});
553567

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

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

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

0 commit comments

Comments
 (0)