Skip to content

Commit 527ed72

Browse files
authored
Cleanup enableFormActions flag (#28614)
Cleanup enableFormActions flag
1 parent e373190 commit 527ed72

30 files changed

+184
-310
lines changed

packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2672,7 +2672,7 @@ describe('ReactHooksInspectionIntegration', () => {
26722672
`);
26732673
});
26742674

2675-
// @gate enableFormActions && enableAsyncActions
2675+
// @gate enableAsyncActions
26762676
it('should support useFormState hook', async () => {
26772677
function Foo() {
26782678
const [value] = ReactDOM.useFormState(function increment(n) {

packages/react-dom-bindings/src/client/ReactDOMComponent.js

Lines changed: 70 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ import {
6969
enableBigIntSupport,
7070
enableCustomElementPropertySupport,
7171
enableClientRenderFallbackOnTextMismatch,
72-
enableFormActions,
7372
disableIEWorkarounds,
7473
enableTrustedTypesIntegration,
7574
enableFilterEmptyStringAttributesDOM,
@@ -498,71 +497,54 @@ function setProp(
498497
if (__DEV__) {
499498
validateFormActionInDevelopment(tag, key, value, props);
500499
}
501-
if (enableFormActions) {
502-
if (typeof value === 'function') {
503-
// Set a javascript URL that doesn't do anything. We don't expect this to be invoked
504-
// because we'll preventDefault, but it can happen if a form is manually submitted or
505-
// if someone calls stopPropagation before React gets the event.
506-
// If CSP is used to block javascript: URLs that's fine too. It just won't show this
507-
// error message but the URL will be logged.
508-
domElement.setAttribute(
509-
key,
510-
// eslint-disable-next-line no-script-url
511-
"javascript:throw new Error('" +
512-
'A React form was unexpectedly submitted. If you called form.submit() manually, ' +
513-
"consider using form.requestSubmit() instead. If you\\'re trying to use " +
514-
'event.stopPropagation() in a submit event handler, consider also calling ' +
515-
'event.preventDefault().' +
516-
"')",
517-
);
518-
break;
519-
} else if (typeof prevValue === 'function') {
520-
// When we're switching off a Server Action that was originally hydrated.
521-
// The server control these fields during SSR that are now trailing.
522-
// The regular diffing doesn't apply since we compare against the previous props.
523-
// Instead, we need to force them to be set to whatever they should be now.
524-
// This would be a lot cleaner if we did this whole fork in the per-tag approach.
525-
if (key === 'formAction') {
526-
if (tag !== 'input') {
527-
// Setting the name here isn't completely safe for inputs if this is switching
528-
// to become a radio button. In that case we let the tag based override take
529-
// control.
530-
setProp(domElement, tag, 'name', props.name, props, null);
531-
}
532-
setProp(
533-
domElement,
534-
tag,
535-
'formEncType',
536-
props.formEncType,
537-
props,
538-
null,
539-
);
540-
setProp(
541-
domElement,
542-
tag,
543-
'formMethod',
544-
props.formMethod,
545-
props,
546-
null,
547-
);
548-
setProp(
549-
domElement,
550-
tag,
551-
'formTarget',
552-
props.formTarget,
553-
props,
554-
null,
555-
);
556-
} else {
557-
setProp(domElement, tag, 'encType', props.encType, props, null);
558-
setProp(domElement, tag, 'method', props.method, props, null);
559-
setProp(domElement, tag, 'target', props.target, props, null);
500+
if (typeof value === 'function') {
501+
// Set a javascript URL that doesn't do anything. We don't expect this to be invoked
502+
// because we'll preventDefault, but it can happen if a form is manually submitted or
503+
// if someone calls stopPropagation before React gets the event.
504+
// If CSP is used to block javascript: URLs that's fine too. It just won't show this
505+
// error message but the URL will be logged.
506+
domElement.setAttribute(
507+
key,
508+
// eslint-disable-next-line no-script-url
509+
"javascript:throw new Error('" +
510+
'A React form was unexpectedly submitted. If you called form.submit() manually, ' +
511+
"consider using form.requestSubmit() instead. If you\\'re trying to use " +
512+
'event.stopPropagation() in a submit event handler, consider also calling ' +
513+
'event.preventDefault().' +
514+
"')",
515+
);
516+
break;
517+
} else if (typeof prevValue === 'function') {
518+
// When we're switching off a Server Action that was originally hydrated.
519+
// The server control these fields during SSR that are now trailing.
520+
// The regular diffing doesn't apply since we compare against the previous props.
521+
// Instead, we need to force them to be set to whatever they should be now.
522+
// This would be a lot cleaner if we did this whole fork in the per-tag approach.
523+
if (key === 'formAction') {
524+
if (tag !== 'input') {
525+
// Setting the name here isn't completely safe for inputs if this is switching
526+
// to become a radio button. In that case we let the tag based override take
527+
// control.
528+
setProp(domElement, tag, 'name', props.name, props, null);
560529
}
530+
setProp(
531+
domElement,
532+
tag,
533+
'formEncType',
534+
props.formEncType,
535+
props,
536+
null,
537+
);
538+
setProp(domElement, tag, 'formMethod', props.formMethod, props, null);
539+
setProp(domElement, tag, 'formTarget', props.formTarget, props, null);
540+
} else {
541+
setProp(domElement, tag, 'encType', props.encType, props, null);
542+
setProp(domElement, tag, 'method', props.method, props, null);
543+
setProp(domElement, tag, 'target', props.target, props, null);
561544
}
562545
}
563546
if (
564547
value == null ||
565-
(!enableFormActions && typeof value === 'function') ||
566548
typeof value === 'symbol' ||
567549
typeof value === 'boolean'
568550
) {
@@ -2435,35 +2417,33 @@ function diffHydratedGenericElement(
24352417
);
24362418
continue;
24372419
case 'action':
2438-
case 'formAction':
2439-
if (enableFormActions) {
2440-
const serverValue = domElement.getAttribute(propKey);
2441-
if (typeof value === 'function') {
2442-
extraAttributes.delete(propKey.toLowerCase());
2443-
// The server can set these extra properties to implement actions.
2444-
// So we remove them from the extra attributes warnings.
2445-
if (propKey === 'formAction') {
2446-
extraAttributes.delete('name');
2447-
extraAttributes.delete('formenctype');
2448-
extraAttributes.delete('formmethod');
2449-
extraAttributes.delete('formtarget');
2450-
} else {
2451-
extraAttributes.delete('enctype');
2452-
extraAttributes.delete('method');
2453-
extraAttributes.delete('target');
2454-
}
2455-
// Ideally we should be able to warn if the server value was not a function
2456-
// however since the function can return any of these attributes any way it
2457-
// wants as a custom progressive enhancement, there's nothing to compare to.
2458-
// We can check if the function has the $FORM_ACTION property on the client
2459-
// and if it's not, warn, but that's an unnecessary constraint that they
2460-
// have to have the extra extension that doesn't do anything on the client.
2461-
continue;
2462-
} else if (serverValue === EXPECTED_FORM_ACTION_URL) {
2463-
extraAttributes.delete(propKey.toLowerCase());
2464-
warnForPropDifference(propKey, 'function', value);
2465-
continue;
2420+
case 'formAction': {
2421+
const serverValue = domElement.getAttribute(propKey);
2422+
if (typeof value === 'function') {
2423+
extraAttributes.delete(propKey.toLowerCase());
2424+
// The server can set these extra properties to implement actions.
2425+
// So we remove them from the extra attributes warnings.
2426+
if (propKey === 'formAction') {
2427+
extraAttributes.delete('name');
2428+
extraAttributes.delete('formenctype');
2429+
extraAttributes.delete('formmethod');
2430+
extraAttributes.delete('formtarget');
2431+
} else {
2432+
extraAttributes.delete('enctype');
2433+
extraAttributes.delete('method');
2434+
extraAttributes.delete('target');
24662435
}
2436+
// Ideally we should be able to warn if the server value was not a function
2437+
// however since the function can return any of these attributes any way it
2438+
// wants as a custom progressive enhancement, there's nothing to compare to.
2439+
// We can check if the function has the $FORM_ACTION property on the client
2440+
// and if it's not, warn, but that's an unnecessary constraint that they
2441+
// have to have the extra extension that doesn't do anything on the client.
2442+
continue;
2443+
} else if (serverValue === EXPECTED_FORM_ACTION_URL) {
2444+
extraAttributes.delete(propKey.toLowerCase());
2445+
warnForPropDifference(propKey, 'function', value);
2446+
continue;
24672447
}
24682448
hydrateSanitizedAttribute(
24692449
domElement,
@@ -2473,6 +2453,7 @@ function diffHydratedGenericElement(
24732453
extraAttributes,
24742454
);
24752455
continue;
2456+
}
24762457
case 'xlinkHref':
24772458
hydrateSanitizedAttribute(
24782459
domElement,

packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ import {
9292
enableCreateEventHandleAPI,
9393
enableScopeAPI,
9494
enableTrustedTypesIntegration,
95-
enableFormActions,
9695
enableAsyncActions,
9796
} from 'shared/ReactFeatureFlags';
9897
import {
@@ -1040,11 +1039,7 @@ export function canHydrateInstance(
10401039
if (element.nodeName.toLowerCase() !== type.toLowerCase()) {
10411040
if (!inRootOrSingleton) {
10421041
// Usually we error for mismatched tags.
1043-
if (
1044-
enableFormActions &&
1045-
element.nodeName === 'INPUT' &&
1046-
(element: any).type === 'hidden'
1047-
) {
1042+
if (element.nodeName === 'INPUT' && (element: any).type === 'hidden') {
10481043
// If we have extra hidden inputs, we don't mismatch. This allows us to embed
10491044
// extra form data in the original form.
10501045
} else {
@@ -1054,11 +1049,7 @@ export function canHydrateInstance(
10541049
// In root or singleton parents we skip past mismatched instances.
10551050
} else if (!inRootOrSingleton) {
10561051
// Match
1057-
if (
1058-
enableFormActions &&
1059-
type === 'input' &&
1060-
(element: any).type === 'hidden'
1061-
) {
1052+
if (type === 'input' && (element: any).type === 'hidden') {
10621053
if (__DEV__) {
10631054
checkAttributeStringCoercion(anyProps.name, 'name');
10641055
}
@@ -1190,7 +1181,6 @@ export function canHydrateTextInstance(
11901181

11911182
while (instance.nodeType !== TEXT_NODE) {
11921183
if (
1193-
enableFormActions &&
11941184
instance.nodeType === ELEMENT_NODE &&
11951185
instance.nodeName === 'INPUT' &&
11961186
(instance: any).type === 'hidden'
@@ -1316,8 +1306,7 @@ function getNextHydratable(node: ?Node) {
13161306
nodeData === SUSPENSE_START_DATA ||
13171307
nodeData === SUSPENSE_FALLBACK_START_DATA ||
13181308
nodeData === SUSPENSE_PENDING_START_DATA ||
1319-
(enableFormActions &&
1320-
enableAsyncActions &&
1309+
(enableAsyncActions &&
13211310
(nodeData === FORM_STATE_IS_MATCHING ||
13221311
nodeData === FORM_STATE_IS_NOT_MATCHING))
13231312
) {
@@ -1512,9 +1501,7 @@ export function commitHydratedSuspenseInstance(
15121501
export function shouldDeleteUnhydratedTailInstances(
15131502
parentType: string,
15141503
): boolean {
1515-
return (
1516-
!enableFormActions || (parentType !== 'form' && parentType !== 'button')
1517-
);
1504+
return parentType !== 'form' && parentType !== 'button';
15181505
}
15191506

15201507
export function didNotMatchHydratedContainerTextInstance(

packages/react-dom-bindings/src/events/DOMPluginEventSystem.js

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ import {
5252
enableLegacyFBSupport,
5353
enableCreateEventHandleAPI,
5454
enableScopeAPI,
55-
enableFormActions,
5655
} from 'shared/ReactFeatureFlags';
5756
import {createEventListenerWrapperWithPriority} from './ReactDOMEventListener';
5857
import {
@@ -169,17 +168,15 @@ function extractEvents(
169168
eventSystemFlags,
170169
targetContainer,
171170
);
172-
if (enableFormActions) {
173-
FormActionEventPlugin.extractEvents(
174-
dispatchQueue,
175-
domEventName,
176-
targetInst,
177-
nativeEvent,
178-
nativeEventTarget,
179-
eventSystemFlags,
180-
targetContainer,
181-
);
182-
}
171+
FormActionEventPlugin.extractEvents(
172+
dispatchQueue,
173+
domEventName,
174+
targetInst,
175+
nativeEvent,
176+
nativeEventTarget,
177+
eventSystemFlags,
178+
targetContainer,
179+
);
183180
}
184181
}
185182

0 commit comments

Comments
 (0)