@samitouri / QOS-React-2 / commits / 106ea1c584

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<T>` in TypeScript, then you can pass any `Iterable<T>` 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

Sebastian Markbåge committed Mar 5, 2023 at 13:18 UTC 106ea1c584d811eda5d328a5f7f856a738c2ca24
2 files changed +35
packages/react-client/src/__tests__/ReactFlight-test.js
+28
@@ -169,6 +169,34 @@ describe('ReactFlight', () => {
169 expect(ReactNoop).toMatchRenderedOutput(<span>Hello, Seb Smith</span>);
170 });
171
172 + it('can render an iterable as an array', async () => {
173 + function ItemListClient(props) {
174 + return <span>{props.items}</span>;
175 + }
176 + const ItemList = clientReference(ItemListClient);
177 +
178 + function Items() {
179 + const iterable = {
180 + [Symbol.iterator]: function* () {
181 + yield 'A';
182 + yield 'B';
183 + yield 'C';
184 + },
185 + };
186 + return <ItemList items={iterable} />;
187 + }
188 +
189 + const model = <Items />;
190 +
191 + const transport = ReactNoopFlightServer.render(model);
192 +
193 + await act(async () => {
194 + ReactNoop.render(await ReactNoopFlightClient.read(transport));
195 + });
196 +
197 + expect(ReactNoop).toMatchRenderedOutput(<span>ABC</span>);
198 + });
199 +
200 it('can render a lazy component as a shared component on the server', async () => {
201 function SharedComponent({text}) {
202 return (
packages/react-server/src/ReactFlightServer.js
+7
@@ -73,6 +73,7 @@ import {
73 } from './ReactFlightNewContext';
74
75 import {
76 + getIteratorFn,
77 REACT_ELEMENT_TYPE,
78 REACT_FORWARD_REF_TYPE,
79 REACT_FRAGMENT_TYPE,
@@ -1059,6 +1060,12 @@ export function resolveModelToJSON(
1060 }
1061 return (undefined: any);
1062 }
1063 + if (!isArray(value)) {
1064 + const iteratorFn = getIteratorFn(value);
1065 + if (iteratorFn) {
1066 + return Array.from((value: any));
1067 + }
1068 + }
1069
1070 if (__DEV__) {
1071 if (value !== null && !isArray(value)) {