[Fiber] Don't set .innerHTML when it hasn't changed (#36949)
[Fiber] Don't set .innerHTML when it hasn't changed (#36949)
Fixes #30994. We compared this previously but it regressed in #26501.
@@ -1283,6 +1283,41 @@ describe('ReactDOMComponent', () => {
1283 1283 expect(container.textContent).toEqual('bonjour');
1284 1284 });
1285 1285
1286 + it('should not incur unnecessary DOM mutations for equal innerHTML', async () => {
1287 + // Regression test for https://github.com/facebook/react/issues/30994.
1288 + // Reassigning equal innerHTML destroys and recreates the child nodes,
1289 + // which breaks in-progress gestures (e.g. swallows an in-flight click
1290 + // when a re-render commits between focus and click) and discards state
1291 + // like text selection.
1292 + const container = document.createElement('div');
1293 + const root = ReactDOMClient.createRoot(container);
1294 + await act(() => {
1295 + root.render(
1296 + <div dangerouslySetInnerHTML={{ __html: 'hi' }} />,
1297 + );
1298 + });
1299 +
1300 + const node = container.firstChild;
1301 + const child = node.firstChild;
1302 +
1303 + // A new object with an equal __html string must not touch the DOM.
1304 + await act(() => {
1305 + root.render(
1306 + <div dangerouslySetInnerHTML={{ __html: 'hi' }} />,
1307 + );
1308 + });
1309 + expect(node.firstChild).toBe(child);
1310 +
1311 + // A different __html string still updates.
1312 + await act(() => {
1313 + root.render(
1314 + <div dangerouslySetInnerHTML={{ __html: 'bye' }} />,
1315 + );
1316 + });
1317 + expect(node.firstChild).not.toBe(child);
1318 + expect(node.innerHTML).toEqual('bye');
1319 + });
1320 +
1286 1321 it('should not incur unnecessary DOM mutations for attributes', async () => {
1287 1322 const container = document.createElement('div');
1288 1323 const root = ReactDOMClient.createRoot(container);
0 commit comments
Comments
No comments yet. Start the discussion.