From 4c5d6f46f303a0cca7deb5e42ab328f2a3d66a2e Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Fri, 28 Apr 2023 01:14:56 -0400 Subject: [PATCH] Allow hidden inputs as extra nodes that we don't match Really this could be limited to just buttons but I just made it a general thing. --- .../src/client/ReactFiberConfigDOM.js | 25 +++++++++++-- .../ReactServerRenderingHydration-test.js | 37 +++++++++++++++++++ 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js index ff7eda12ff162..eb0b2f961bfb0 100644 --- a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js +++ b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js @@ -1047,20 +1047,39 @@ export function canHydrateInstance( ): null | Instance { while (instance.nodeType === ELEMENT_NODE) { const element: Element = (instance: any); + const anyProps = (props: any); if (element.nodeName.toLowerCase() !== type.toLowerCase()) { if (!inRootOrSingleton || !enableHostSingletons) { // Usually we error for mismatched tags. - return null; + if ( + enableFormActions && + element.nodeName === 'INPUT' && + (element: any).type === 'hidden' + ) { + // If we have extra hidden inputs, we don't mismatch. This allows us to embed + // extra form data in the original form. + } else { + return null; + } } // In root or singleton parents we skip past mismatched instances. } else if (!inRootOrSingleton || !enableHostSingletons) { // Match - return element; + if ( + enableFormActions && + type === 'input' && + (element: any).type === 'hidden' && + anyProps.type !== 'hidden' + ) { + // Skip past hidden inputs unless that's what we're looking for. This allows us + // embed extra form data in the original form. + } else { + return element; + } } else if (isMarkedHoistable(element)) { // We've already claimed this as a hoistable which isn't hydrated this way so we skip past it. } else { // We have an Element with the right type. - const anyProps = (props: any); // We are going to try to exclude it if we can definitely identify it as a hoisted Node or if // we can guess that the node is likely hoisted or was inserted by a 3rd party script or browser extension diff --git a/packages/react-dom/src/__tests__/ReactServerRenderingHydration-test.js b/packages/react-dom/src/__tests__/ReactServerRenderingHydration-test.js index a9ae22f1f5676..55221001c4540 100644 --- a/packages/react-dom/src/__tests__/ReactServerRenderingHydration-test.js +++ b/packages/react-dom/src/__tests__/ReactServerRenderingHydration-test.js @@ -695,4 +695,41 @@ describe('ReactDOMServerHydration', () => { ); } }); + + // @gate enableFormActions + it('allows rendering extra hidden inputs in a form', async () => { + const element = document.createElement('div'); + element.innerHTML = + '
' + + '' + + '' + + '