Skip to content

Commit a08ae9f

Browse files
authored
Listen to onScroll during hydration (#19803)
1 parent 781212a commit a08ae9f

File tree

2 files changed

+108
-0
lines changed

2 files changed

+108
-0
lines changed

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

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
1212
describe('ReactDOMEventListener', () => {
1313
let React;
1414
let ReactDOM;
15+
let ReactDOMServer;
1516

1617
beforeEach(() => {
1718
jest.resetModules();
1819
React = require('react');
1920
ReactDOM = require('react-dom');
21+
ReactDOMServer = require('react-dom/server');
2022
});
2123

2224
describe('Propagation', () => {
@@ -797,4 +799,108 @@ describe('ReactDOMEventListener', () => {
797799
document.body.removeChild(container);
798800
}
799801
});
802+
803+
it('should subscribe to scroll during updates', () => {
804+
const container = document.createElement('div');
805+
const ref = React.createRef();
806+
const log = [];
807+
const onScroll = jest.fn(e =>
808+
log.push(['bubble', e.currentTarget.className]),
809+
);
810+
const onScrollCapture = jest.fn(e =>
811+
log.push(['capture', e.currentTarget.className]),
812+
);
813+
document.body.appendChild(container);
814+
try {
815+
ReactDOM.render(
816+
<div>
817+
<div>
818+
<div />
819+
</div>
820+
</div>,
821+
container,
822+
);
823+
ReactDOM.render(
824+
<div
825+
className="grand"
826+
onScroll={onScroll}
827+
onScrollCapture={onScrollCapture}>
828+
<div
829+
className="parent"
830+
onScroll={onScroll}
831+
onScrollCapture={onScrollCapture}>
832+
<div
833+
className="child"
834+
onScroll={onScroll}
835+
onScrollCapture={onScrollCapture}
836+
ref={ref}
837+
/>
838+
</div>
839+
</div>,
840+
container,
841+
);
842+
ref.current.dispatchEvent(
843+
new Event('scroll', {
844+
bubbles: false,
845+
}),
846+
);
847+
expect(log).toEqual([
848+
['capture', 'grand'],
849+
['capture', 'parent'],
850+
['capture', 'child'],
851+
['bubble', 'child'],
852+
]);
853+
} finally {
854+
document.body.removeChild(container);
855+
}
856+
});
857+
858+
// Regression test.
859+
it('should subscribe to scroll during hydration', () => {
860+
const container = document.createElement('div');
861+
const ref = React.createRef();
862+
const log = [];
863+
const onScroll = jest.fn(e =>
864+
log.push(['bubble', e.currentTarget.className]),
865+
);
866+
const onScrollCapture = jest.fn(e =>
867+
log.push(['capture', e.currentTarget.className]),
868+
);
869+
const tree = (
870+
<div
871+
className="grand"
872+
onScroll={onScroll}
873+
onScrollCapture={onScrollCapture}>
874+
<div
875+
className="parent"
876+
onScroll={onScroll}
877+
onScrollCapture={onScrollCapture}>
878+
<div
879+
className="child"
880+
onScroll={onScroll}
881+
onScrollCapture={onScrollCapture}
882+
ref={ref}
883+
/>
884+
</div>
885+
</div>
886+
);
887+
document.body.appendChild(container);
888+
try {
889+
container.innerHTML = ReactDOMServer.renderToString(tree);
890+
ReactDOM.hydrate(tree, container);
891+
ref.current.dispatchEvent(
892+
new Event('scroll', {
893+
bubbles: false,
894+
}),
895+
);
896+
expect(log).toEqual([
897+
['capture', 'grand'],
898+
['capture', 'parent'],
899+
['capture', 'child'],
900+
['bubble', 'child'],
901+
]);
902+
} finally {
903+
document.body.removeChild(container);
904+
}
905+
});
800906
});

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,6 +1086,8 @@ export function diffHydratedProperties(
10861086
}
10871087
if (!enableEagerRootListeners) {
10881088
ensureListeningTo(rootContainerElement, propKey, domElement);
1089+
} else if (propKey === 'onScroll') {
1090+
listenToNonDelegatedEvent('scroll', domElement);
10891091
}
10901092
}
10911093
} else if (

0 commit comments

Comments
 (0)