React version: Any
React Developer Tools: 4.8.2
function* makeCounter() {
let c = 0;
while (true) {
yield c++;
}
}
const counter = makeCounter();
const Sample = () => <Component counter={counter} />;
open chrome devtools and select this component with React Dev Tools (Components tab)
crashes after few seconds
Link to code example:
https://codesandbox.io/s/happy-lake-c1vyf?file=/src/App.js
The page crashes due to devtools crash.
devtools doesn't crash.
This is because ReactDevTools is trying to display elements inside iterator object with transforming it into array here: https://github.com/facebook/react/blob/b6e1d086043a801682ff01b00c7a623d529b46c0/packages/react-devtools-shared/src/utils.js#L606
Iterators could be generally infinite (and also have side effect, like counter in the example). So I think it should not be extracted to array here.
The code you described is not the same as in your codesandbox. Your codesandbox is problematic as is since its render function has a side-effect:
export default class Sample extends React.Component {
render() {
const counter = makeCounter();
// ^^^^^^^^^^^^^ every time render runs (with the same input) the output is different
return <GeneratorInProps counter={counter} />;
}
}
Devtools might work under the assumption that render is side-effect free and thus crash.
The code you described works fine: https://codesandbox.io/s/dawn-cdn-gf1m0?file=/src/App.js. So this might just be an issue that class components are treated differently.
The question is if devtools should not handle this and simply crash or guard against render functions with infinite iterators.
Thanks, @eps1lon .
Sorry, side-effect here was my misleading. I had to say that extracting iterator with Array.from to display props in devtools could cause unexpected crash with infinite iterator.
The question is if devtools should not handle this and simply crash or guard against render functions with infinite iterators.
Yes, this is my point. I think there are 3 choices:
In my case, current behavior was really unexpected because I was simply passing a counter (infinite iterator) to props, and just counting inside a handler in a descendant component. 2 or 3 behavior is helpful for me.
Yeah an infinite iterator is not inherently bad. You could use it safely by calling next() in an effect. The line you mentioned should probably iterate incrementally until some big number and then stop.
Since you already identified the line of code would you mind opening a PR?
Could you check if it's even safe for devtools to iterate over an iterator? wouldn't this change the behavior of the components using since devtools already moved the pointer ahead?
Can I take this one ?
Can I take this one ?
Sure thing. Go ahead.
Could you check if it's even safe for devtools to iterate over an iterator? wouldn't this change the behavior of the components using since devtools already moved the pointer ahead?
Quickly tested it myself and devtools don't seem to interfere with the generator state.
Updated my example: https://codesandbox.io/s/happy-lake-c1vyf?file=/src/App.js
After selecting the component includes infinite iterator, devtools hang up few seconds and crashed.

If I set infinite loop protection true in sandbox.config.json, then loop aborts and codesandbox shows this log:
tryCatch
https://codesandbox.io/static/js/sandbox.f03e10a51.js:1:201658
Generator.invoke [as _invoke]
https://codesandbox.io/static/js/sandbox.f03e10a51.js:1:201658
Generator.prototype.<computed> [as next]
https://codesandbox.io/static/js/sandbox.f03e10a51.js:1:201658
formatDataForPreview
chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/react_devtools_backend.js:839:27
dehydrate
chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/react_devtools_backend.js:1445:100
dehydrate
chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/react_devtools_backend.js:1492:26
cleanForBridge
chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/react_devtools_backend.js:1085:91
Object.inspectElement
chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/react_devtools_backend.js:5376:108
(anonymous function)
chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/react_devtools_backend.js:8559:57
Bridge.emit
chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/react_devtools_backend.js:2349:20
(anonymous function)
chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/react_devtools_backend.js:12126:37
listener
chrome-extension://fmkadmapgofadopljbjfkapdkoienihi/build/react_devtools_backend.js:9759:9
I have a fix but it鈥檚 related to what @gaearon says in https://github.com/facebook/react/issues/19726 . I don鈥檛 know if I can publish it?
I have a fix but it鈥檚 related to what @gaearon says in #19726 . I don鈥檛 know if I can publish it?
That issue has already someone working on it. Please be so kind and wait with the PR. If the assigned person stops working on it you can go ahead and propose your change.
Ok I鈥檒l wait @todortotev before I publish my PR.
is the solution to this now available?
function* makeFiniteCounter(n) {
let c = 0;
while (c < n) {
yield c++;
}
}
if (makeFiniteCounter().toString() === '[object Generator]') {
do something .............
}
Knowing that it is a generator might allow you to differentiate from an iterable and process accordingly
This should be resolved by #19831 once it lands.