Skip to content

Commit 19bc2dd

Browse files
koba04gaearon
authored andcommitted
Fix autoFocus for hydration content when it is mismatched (#11737)
* Fix autoFocus for hydration content when it is mismatched * Add a test for mismatched content * Fix a test for production * Fix a spec description and verify console.error output * Run prettier * finalizeInitialChildren always returns `true` * Revert "finalizeInitialChildren always returns `true`" This reverts commit 58edd22. * Add a TODO comment * Update ReactServerRendering-test.js * Update ReactServerRendering-test.js * Rewrite the comment
1 parent 5bd2321 commit 19bc2dd

File tree

2 files changed

+35
-5
lines changed

2 files changed

+35
-5
lines changed

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

+22
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,28 @@ describe('ReactDOMServer', () => {
372372
expect(element.firstChild.focus).not.toHaveBeenCalled();
373373
});
374374

375+
// Regression test for https://github.com/facebook/react/issues/11726
376+
it('should not focus on either server or client with autofocus={false} even if there is a markup mismatch', () => {
377+
spyOnDev(console, 'error');
378+
379+
var element = document.createElement('div');
380+
element.innerHTML = ReactDOMServer.renderToString(
381+
<button autoFocus={false}>server</button>,
382+
);
383+
expect(element.firstChild.autofocus).toBe(false);
384+
385+
element.firstChild.focus = jest.fn();
386+
ReactDOM.hydrate(<button autoFocus={false}>client</button>, element);
387+
388+
expect(element.firstChild.focus).not.toHaveBeenCalled();
389+
if (__DEV__) {
390+
expect(console.error.calls.count()).toBe(1);
391+
expect(console.error.calls.argsFor(0)[0]).toBe(
392+
'Warning: Text content did not match. Server: "server" Client: "client"',
393+
);
394+
}
395+
});
396+
375397
it('should throw with silly args', () => {
376398
expect(
377399
ReactDOMServer.renderToString.bind(ReactDOMServer, {x: 123}),

packages/react-dom/src/client/ReactDOM.js

+13-5
Original file line numberDiff line numberDiff line change
@@ -704,11 +704,19 @@ const DOMRenderer = ReactFiberReconciler({
704704
newProps: Props,
705705
internalInstanceHandle: Object,
706706
): void {
707-
((domElement: any):
708-
| HTMLButtonElement
709-
| HTMLInputElement
710-
| HTMLSelectElement
711-
| HTMLTextAreaElement).focus();
707+
// Despite the naming that might imply otherwise, this method only
708+
// fires if there is an `Update` effect scheduled during mounting.
709+
// This happens if `finalizeInitialChildren` returns `true` (which it
710+
// does to implement the `autoFocus` attribute on the client). But
711+
// there are also other cases when this might happen (such as patching
712+
// up text content during hydration mismatch). So we'll check this again.
713+
if (shouldAutoFocusHostComponent(type, newProps)) {
714+
((domElement: any):
715+
| HTMLButtonElement
716+
| HTMLInputElement
717+
| HTMLSelectElement
718+
| HTMLTextAreaElement).focus();
719+
}
712720
},
713721

714722
commitUpdate(

0 commit comments

Comments
 (0)