From f39a29ba676d3561420d7a00b053ea1c1bc97c26 Mon Sep 17 00:00:00 2001 From: eps1lon Date: Fri, 29 Apr 2022 18:40:41 +0200 Subject: [PATCH 1/3] Warn when using one-shot iterators as children --- .../src/__tests__/ReactMultiChild-test.js | 23 +++++++++++++++++++ .../src/ReactChildFiber.new.js | 17 ++++++++++++++ .../src/ReactChildFiber.old.js | 17 ++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/packages/react-dom/src/__tests__/ReactMultiChild-test.js b/packages/react-dom/src/__tests__/ReactMultiChild-test.js index 2f76f33270dec..c7cb8ed0493c8 100644 --- a/packages/react-dom/src/__tests__/ReactMultiChild-test.js +++ b/packages/react-dom/src/__tests__/ReactMultiChild-test.js @@ -323,6 +323,29 @@ describe('ReactMultiChild', () => { ReactDOM.render(, div); }); + it('should warn when using one-shot iterators as children', () => { + function Foo() { + const iterator = [

Hello

,

Dave

].values(); + + return iterator; + } + + const div = document.createElement('div'); + expect(() => { + ReactDOM.render(, div); + }).toErrorDev( + 'Using a TOOD-understandable-term as children is unsupported and will likely yield ' + + 'unexpected results because enumerating a TOOD-understandable-term mutates it. ' + + 'You may convert it to an array with `Array.from()` or the ' + + '`[...spread]` operator before rendering. Keep in mind ' + + 'you might need to polyfill these features for older browsers.\n' + + ' in Foo (at **)', + ); + + // Test de-duplication + ReactDOM.render(, div); + }); + it('should not warn for using generators in legacy iterables', () => { const fooIterable = { '@@iterator': function*() { diff --git a/packages/react-reconciler/src/ReactChildFiber.new.js b/packages/react-reconciler/src/ReactChildFiber.new.js index 2e1a232e028db..3b53ad06a348b 100644 --- a/packages/react-reconciler/src/ReactChildFiber.new.js +++ b/packages/react-reconciler/src/ReactChildFiber.new.js @@ -47,6 +47,7 @@ import {pushTreeFork} from './ReactFiberTreeContext.new'; let didWarnAboutMaps; let didWarnAboutGenerators; +let didWarnAboutOneShotIterators; let didWarnAboutStringRefs; let ownerHasKeyUseWarning; let ownerHasFunctionTypeWarning; @@ -955,6 +956,22 @@ function ChildReconciler(shouldTrackSideEffects) { didWarnAboutMaps = true; } + // Warn about using one-shot iterators as children + const isOneShotIterator = + iteratorFn.call(newChildrenIterable) === newChildrenIterable; + if (isOneShotIterator) { + if (!didWarnAboutOneShotIterators) { + console.error( + 'Using a TOOD-understandable-term as children is unsupported and will likely yield ' + + 'unexpected results because enumerating a TOOD-understandable-term mutates it. ' + + 'You may convert it to an array with `Array.from()` or the ' + + '`[...spread]` operator before rendering. Keep in mind ' + + 'you might need to polyfill these features for older browsers.', + ); + } + didWarnAboutOneShotIterators = true; + } + // First, validate keys. // We'll get a different iterator later for the main pass. const newChildren = iteratorFn.call(newChildrenIterable); diff --git a/packages/react-reconciler/src/ReactChildFiber.old.js b/packages/react-reconciler/src/ReactChildFiber.old.js index c6fdbcc728a29..65cbc5e7ecc00 100644 --- a/packages/react-reconciler/src/ReactChildFiber.old.js +++ b/packages/react-reconciler/src/ReactChildFiber.old.js @@ -47,6 +47,7 @@ import {pushTreeFork} from './ReactFiberTreeContext.old'; let didWarnAboutMaps; let didWarnAboutGenerators; +let didWarnAboutOneShotIterators; let didWarnAboutStringRefs; let ownerHasKeyUseWarning; let ownerHasFunctionTypeWarning; @@ -955,6 +956,22 @@ function ChildReconciler(shouldTrackSideEffects) { didWarnAboutMaps = true; } + // Warn about using one-shot iterators as children + const isOneShotIterator = + iteratorFn.call(newChildrenIterable) === newChildrenIterable; + if (isOneShotIterator) { + if (!didWarnAboutOneShotIterators) { + console.error( + 'Using a TOOD-understandable-term as children is unsupported and will likely yield ' + + 'unexpected results because enumerating a TOOD-understandable-term mutates it. ' + + 'You may convert it to an array with `Array.from()` or the ' + + '`[...spread]` operator before rendering. Keep in mind ' + + 'you might need to polyfill these features for older browsers.', + ); + } + didWarnAboutOneShotIterators = true; + } + // First, validate keys. // We'll get a different iterator later for the main pass. const newChildren = iteratorFn.call(newChildrenIterable); From 37a52244faec5e8a5e4a75c4dfe4e2bafbbfe01e Mon Sep 17 00:00:00 2001 From: eps1lon Date: Fri, 29 Apr 2022 18:59:49 +0200 Subject: [PATCH 2/3] generators are one-shot iterators --- .../src/ReactChildFiber.new.js | 32 +++++++++---------- .../src/ReactChildFiber.old.js | 32 +++++++++---------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/packages/react-reconciler/src/ReactChildFiber.new.js b/packages/react-reconciler/src/ReactChildFiber.new.js index 3b53ad06a348b..28920c3435e30 100644 --- a/packages/react-reconciler/src/ReactChildFiber.new.js +++ b/packages/react-reconciler/src/ReactChildFiber.new.js @@ -943,6 +943,22 @@ function ChildReconciler(shouldTrackSideEffects) { ); } didWarnAboutGenerators = true; + } else { + // Warn about using one-shot iterators as children + const isOneShotIterator = + iteratorFn.call(newChildrenIterable) === newChildrenIterable; + if (isOneShotIterator) { + if (!didWarnAboutOneShotIterators) { + console.error( + 'Using a TOOD-understandable-term as children is unsupported and will likely yield ' + + 'unexpected results because enumerating a TOOD-understandable-term mutates it. ' + + 'You may convert it to an array with `Array.from()` or the ' + + '`[...spread]` operator before rendering. Keep in mind ' + + 'you might need to polyfill these features for older browsers.', + ); + } + didWarnAboutOneShotIterators = true; + } } // Warn about using Maps as children @@ -956,22 +972,6 @@ function ChildReconciler(shouldTrackSideEffects) { didWarnAboutMaps = true; } - // Warn about using one-shot iterators as children - const isOneShotIterator = - iteratorFn.call(newChildrenIterable) === newChildrenIterable; - if (isOneShotIterator) { - if (!didWarnAboutOneShotIterators) { - console.error( - 'Using a TOOD-understandable-term as children is unsupported and will likely yield ' + - 'unexpected results because enumerating a TOOD-understandable-term mutates it. ' + - 'You may convert it to an array with `Array.from()` or the ' + - '`[...spread]` operator before rendering. Keep in mind ' + - 'you might need to polyfill these features for older browsers.', - ); - } - didWarnAboutOneShotIterators = true; - } - // First, validate keys. // We'll get a different iterator later for the main pass. const newChildren = iteratorFn.call(newChildrenIterable); diff --git a/packages/react-reconciler/src/ReactChildFiber.old.js b/packages/react-reconciler/src/ReactChildFiber.old.js index 65cbc5e7ecc00..be10134640920 100644 --- a/packages/react-reconciler/src/ReactChildFiber.old.js +++ b/packages/react-reconciler/src/ReactChildFiber.old.js @@ -943,6 +943,22 @@ function ChildReconciler(shouldTrackSideEffects) { ); } didWarnAboutGenerators = true; + } else { + // Warn about using one-shot iterators as children + const isOneShotIterator = + iteratorFn.call(newChildrenIterable) === newChildrenIterable; + if (isOneShotIterator) { + if (!didWarnAboutOneShotIterators) { + console.error( + 'Using a TOOD-understandable-term as children is unsupported and will likely yield ' + + 'unexpected results because enumerating a TOOD-understandable-term mutates it. ' + + 'You may convert it to an array with `Array.from()` or the ' + + '`[...spread]` operator before rendering. Keep in mind ' + + 'you might need to polyfill these features for older browsers.', + ); + } + didWarnAboutOneShotIterators = true; + } } // Warn about using Maps as children @@ -956,22 +972,6 @@ function ChildReconciler(shouldTrackSideEffects) { didWarnAboutMaps = true; } - // Warn about using one-shot iterators as children - const isOneShotIterator = - iteratorFn.call(newChildrenIterable) === newChildrenIterable; - if (isOneShotIterator) { - if (!didWarnAboutOneShotIterators) { - console.error( - 'Using a TOOD-understandable-term as children is unsupported and will likely yield ' + - 'unexpected results because enumerating a TOOD-understandable-term mutates it. ' + - 'You may convert it to an array with `Array.from()` or the ' + - '`[...spread]` operator before rendering. Keep in mind ' + - 'you might need to polyfill these features for older browsers.', - ); - } - didWarnAboutOneShotIterators = true; - } - // First, validate keys. // We'll get a different iterator later for the main pass. const newChildren = iteratorFn.call(newChildrenIterable); From 1610922e9dda667315faf8ea2d520d757b4cfef4 Mon Sep 17 00:00:00 2001 From: eps1lon Date: Thu, 29 Sep 2022 20:05:16 +0200 Subject: [PATCH 3/3] Use example rather than coining a term --- packages/react-dom/src/__tests__/ReactMultiChild-test.js | 6 +++--- packages/react-reconciler/src/ReactChildFiber.new.js | 6 +++--- packages/react-reconciler/src/ReactChildFiber.old.js | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/react-dom/src/__tests__/ReactMultiChild-test.js b/packages/react-dom/src/__tests__/ReactMultiChild-test.js index c7cb8ed0493c8..bfde5afe7c124 100644 --- a/packages/react-dom/src/__tests__/ReactMultiChild-test.js +++ b/packages/react-dom/src/__tests__/ReactMultiChild-test.js @@ -334,10 +334,10 @@ describe('ReactMultiChild', () => { expect(() => { ReactDOM.render(, div); }).toErrorDev( - 'Using a TOOD-understandable-term as children is unsupported and will likely yield ' + - 'unexpected results because enumerating a TOOD-understandable-term mutates it. ' + + 'Warning: Using an iterator such as `[].values()` as children is unsupported and will likely yield ' + + 'unexpected results because enumerating such an iterator mutates it. ' + 'You may convert it to an array with `Array.from()` or the ' + - '`[...spread]` operator before rendering. Keep in mind ' + + '`[...spread]` operator before rendering. Keep in mind that ' + 'you might need to polyfill these features for older browsers.\n' + ' in Foo (at **)', ); diff --git a/packages/react-reconciler/src/ReactChildFiber.new.js b/packages/react-reconciler/src/ReactChildFiber.new.js index 28920c3435e30..1ebdc4bfcc885 100644 --- a/packages/react-reconciler/src/ReactChildFiber.new.js +++ b/packages/react-reconciler/src/ReactChildFiber.new.js @@ -950,10 +950,10 @@ function ChildReconciler(shouldTrackSideEffects) { if (isOneShotIterator) { if (!didWarnAboutOneShotIterators) { console.error( - 'Using a TOOD-understandable-term as children is unsupported and will likely yield ' + - 'unexpected results because enumerating a TOOD-understandable-term mutates it. ' + + 'Using an iterator such as `[].values()` as children is unsupported and will likely yield ' + + 'unexpected results because enumerating such an iterator mutates it. ' + 'You may convert it to an array with `Array.from()` or the ' + - '`[...spread]` operator before rendering. Keep in mind ' + + '`[...spread]` operator before rendering. Keep in mind that ' + 'you might need to polyfill these features for older browsers.', ); } diff --git a/packages/react-reconciler/src/ReactChildFiber.old.js b/packages/react-reconciler/src/ReactChildFiber.old.js index be10134640920..3fc28aedd5dff 100644 --- a/packages/react-reconciler/src/ReactChildFiber.old.js +++ b/packages/react-reconciler/src/ReactChildFiber.old.js @@ -950,10 +950,10 @@ function ChildReconciler(shouldTrackSideEffects) { if (isOneShotIterator) { if (!didWarnAboutOneShotIterators) { console.error( - 'Using a TOOD-understandable-term as children is unsupported and will likely yield ' + - 'unexpected results because enumerating a TOOD-understandable-term mutates it. ' + + 'Using an iterator such as `[].values()` as children is unsupported and will likely yield ' + + 'unexpected results because enumerating such an iterator mutates it. ' + 'You may convert it to an array with `Array.from()` or the ' + - '`[...spread]` operator before rendering. Keep in mind ' + + '`[...spread]` operator before rendering. Keep in mind that ' + 'you might need to polyfill these features for older browsers.', ); }