From 106ea1c584d811eda5d328a5f7f856a738c2ca24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Sun, 5 Mar 2023 13:18:54 -0500 Subject: [PATCH] Support Iterables in Flight (#26313) We support any super type of anything that we can serialize. Meaning that as long as the Type that's passed through is less precise, it means that we can encoded it as any subtype and therefore the incoming type doesn't have to be the subtype in that case. Basically, as long as you're only passing through an `Iterable` in TypeScript, then you can pass any `Iterable` and we'll treat it as an array. For example we support Promises *and* Thenables but both are encoded as Promises. We support Arrays and since Arrays are also Iterables, we can support Iterables. For @wongmjane --- .../src/__tests__/ReactFlight-test.js | 28 +++++++++++++++++++ .../react-server/src/ReactFlightServer.js | 7 +++++ 2 files changed, 35 insertions(+) diff --git a/packages/react-client/src/__tests__/ReactFlight-test.js b/packages/react-client/src/__tests__/ReactFlight-test.js index 9495b476d6837..b5ca64d9a2e84 100644 --- a/packages/react-client/src/__tests__/ReactFlight-test.js +++ b/packages/react-client/src/__tests__/ReactFlight-test.js @@ -169,6 +169,34 @@ describe('ReactFlight', () => { expect(ReactNoop).toMatchRenderedOutput(Hello, Seb Smith); }); + it('can render an iterable as an array', async () => { + function ItemListClient(props) { + return {props.items}; + } + const ItemList = clientReference(ItemListClient); + + function Items() { + const iterable = { + [Symbol.iterator]: function* () { + yield 'A'; + yield 'B'; + yield 'C'; + }, + }; + return ; + } + + const model = ; + + const transport = ReactNoopFlightServer.render(model); + + await act(async () => { + ReactNoop.render(await ReactNoopFlightClient.read(transport)); + }); + + expect(ReactNoop).toMatchRenderedOutput(ABC); + }); + it('can render a lazy component as a shared component on the server', async () => { function SharedComponent({text}) { return ( diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index 8c46443b3980a..17e1c7aca83c5 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -73,6 +73,7 @@ import { } from './ReactFlightNewContext'; import { + getIteratorFn, REACT_ELEMENT_TYPE, REACT_FORWARD_REF_TYPE, REACT_FRAGMENT_TYPE, @@ -1059,6 +1060,12 @@ export function resolveModelToJSON( } return (undefined: any); } + if (!isArray(value)) { + const iteratorFn = getIteratorFn(value); + if (iteratorFn) { + return Array.from((value: any)); + } + } if (__DEV__) { if (value !== null && !isArray(value)) {