From a08ae9f147a716520a089055e2dec8f5397a4b0f Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Thu, 10 Sep 2020 11:00:02 +0100 Subject: [PATCH] Listen to onScroll during hydration (#19803) --- .../__tests__/ReactDOMEventListener-test.js | 106 ++++++++++++++++++ .../react-dom/src/client/ReactDOMComponent.js | 2 + 2 files changed, 108 insertions(+) diff --git a/packages/react-dom/src/__tests__/ReactDOMEventListener-test.js b/packages/react-dom/src/__tests__/ReactDOMEventListener-test.js index 1e6169cb5588c..a6918c69197e1 100644 --- a/packages/react-dom/src/__tests__/ReactDOMEventListener-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMEventListener-test.js @@ -12,11 +12,13 @@ describe('ReactDOMEventListener', () => { let React; let ReactDOM; + let ReactDOMServer; beforeEach(() => { jest.resetModules(); React = require('react'); ReactDOM = require('react-dom'); + ReactDOMServer = require('react-dom/server'); }); describe('Propagation', () => { @@ -797,4 +799,108 @@ describe('ReactDOMEventListener', () => { document.body.removeChild(container); } }); + + it('should subscribe to scroll during updates', () => { + const container = document.createElement('div'); + const ref = React.createRef(); + const log = []; + const onScroll = jest.fn(e => + log.push(['bubble', e.currentTarget.className]), + ); + const onScrollCapture = jest.fn(e => + log.push(['capture', e.currentTarget.className]), + ); + document.body.appendChild(container); + try { + ReactDOM.render( +
+
+
+
+
, + container, + ); + ReactDOM.render( +
+
+
+
+
, + container, + ); + ref.current.dispatchEvent( + new Event('scroll', { + bubbles: false, + }), + ); + expect(log).toEqual([ + ['capture', 'grand'], + ['capture', 'parent'], + ['capture', 'child'], + ['bubble', 'child'], + ]); + } finally { + document.body.removeChild(container); + } + }); + + // Regression test. + it('should subscribe to scroll during hydration', () => { + const container = document.createElement('div'); + const ref = React.createRef(); + const log = []; + const onScroll = jest.fn(e => + log.push(['bubble', e.currentTarget.className]), + ); + const onScrollCapture = jest.fn(e => + log.push(['capture', e.currentTarget.className]), + ); + const tree = ( +
+
+
+
+
+ ); + document.body.appendChild(container); + try { + container.innerHTML = ReactDOMServer.renderToString(tree); + ReactDOM.hydrate(tree, container); + ref.current.dispatchEvent( + new Event('scroll', { + bubbles: false, + }), + ); + expect(log).toEqual([ + ['capture', 'grand'], + ['capture', 'parent'], + ['capture', 'child'], + ['bubble', 'child'], + ]); + } finally { + document.body.removeChild(container); + } + }); }); diff --git a/packages/react-dom/src/client/ReactDOMComponent.js b/packages/react-dom/src/client/ReactDOMComponent.js index 48b979af64c94..a228b15647945 100644 --- a/packages/react-dom/src/client/ReactDOMComponent.js +++ b/packages/react-dom/src/client/ReactDOMComponent.js @@ -1086,6 +1086,8 @@ export function diffHydratedProperties( } if (!enableEagerRootListeners) { ensureListeningTo(rootContainerElement, propKey, domElement); + } else if (propKey === 'onScroll') { + listenToNonDelegatedEvent('scroll', domElement); } } } else if (