-
Notifications
You must be signed in to change notification settings - Fork 46.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bug: Iterator as JSX children doesn't work right #20707
Comments
React only accepts immutable input. A one-shot iterator wouldn't be immutable and so is not supported. Only iterables that can produce multiple iterators over the same immutable input are supported. A user space description of why this is important might be something like this:
This component itself might rerender multiple times without the parent doing so. Therefore if you pass a one-shot iterable in to this component - rerendering wouldn't work. It'd suggest you explore Number.range returning an iterable that can produce multiple iterators over the same range since the input range is immutable. (I think we'd probably want to object to a collection approach that is one shot and not compatible with an immutable approach. Like you shouldn't need to use toArray for something like this since it's inefficient.) |
Can we somehow detect a one-shot iterator? Maybe some check like |
I really think it was a mistake for |
Yes, we explored this a lot but it's hard to change to iterable instead of one-shot iterator (see discussion in tc39/proposal-iterator.range#17, tc39/proposal-iterator.range#41 and tc39/proposal-iterator.range#42) |
At the end of the day, with a reusable iterable you can always get a one-shot iterator out of it but you can't get a reusable out of a one-iterator except by allocating the full memory at which point the whole point of iterables are defeated. React is a good example of a use case where you can't use a one-shot. It's a very common paradigm in JS. Since you can't use a one-shot and toArray defeats the purpose, your only option will be to use a third party user space library. If this pattern is useful enough, it'll eventually get added to the language as the reusable iterable form. So it seems inevitable that either there's two APIs or just reusable iterable. |
I definitely support the iterable but others don't agree. |
Unfortunately there's nothing we can do to support it but we can create a more descriptive error message. |
Since react consume the iterator twice, react can warn if the second consume doesn't get the same array length as the first consume |
I totally agree with @sebmarkbage .
Not only C#, but also Python, Ruby, Kotlin, Swift... all got it right. I did a little research on the usage of lodash-range (which create an array, just like range in Python 2, and array of coz not a one-shot iterator but a reusable iterable), and found there is a common usage of So if range proposal eventually choose iterator semantic, it means React users very likely can't use such API in common cases and just bring frustration when they try to use new JS range API and found that not work as expect. |
We don't need to depend on iterator helper proposal, we could make range behave like immutable Array (like Tuple proposal do), so it could have |
@gaearon All iterators are one-shot, so you could warn on a plain object with a I really don't understand the use case though - if you're passing an iterator to React, you're expecting React to consume every item, so why would you not reify it to an array first? |
Yes u should (convert it to array). The problem is many people actually:
|
A lot of time it's more efficient to toArray at some intermediate points because it's worth materialize the memory over reexecuting it but not all. I don't think it's usually when it's passed into React itself but to an intermediate:
In this case, it might be unnecessary to materialize the initial array and intermediate array. But it needs to be multi-shot since the inner component can rerender without rerendering a parent component. But again, it's probably mostly best practice to materialize to an array when it passes a component boundary just because memoization is better than recomputation for updates. |
The main situation where I'm bumping up against this limitation is when using |
This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment! |
bump |
If we don't have progress on this, at least we can make this first.
|
This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment! |
bump |
This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment! |
Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please create a new issue with up-to-date information. Thank you! |
React version: 17
Steps To Reproduce
Link to code example:
https://codesandbox.io/s/react-playground-forked-jv4p5?fontsize=14&hidenavigation=1&theme=dark
The current behavior
Nothing rendered.
React consumes the iterator twice so the items are gone. The first consume is to validate the JSX, the second consume is collecting them as children.
The expected behavior
Render JSX items in the list.
Why I'm considering this case is because I'm investigating how React will work with the ES Number.range proposal.
It seems like they can work in this way:
Without appending
.toArray()
(iterator helper proposal) to the end. It seems like React does support iterators but used it in the wrong way.The text was updated successfully, but these errors were encountered: