Skip to content

Commit dee1164

Browse files
author
Brian Vaughn
committed
Merged master and resolved useEvent conflicts
I am being a little lazy here and merging instead of rebasing because practically every commit conflicted with Dominic's recent useEvent PR. If anyone feel strongly about this, I will revert the commit and rebase. Since the commit will be squashes away during the merge though, I don't think it matters much at this point.
2 parents 45ed506 + 30a998d commit dee1164

File tree

53 files changed

+1299
-454
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+1299
-454
lines changed

fixtures/flight-browser/index.html

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,7 @@ <h1>Flight Example</h1>
5757

5858
let model = {
5959
title: <Title />,
60-
content: {
61-
__html: <HTML />,
62-
}
60+
content: <HTML />,
6361
};
6462

6563
let stream = ReactFlightDOMServer.renderToReadableStream(model);
@@ -90,7 +88,7 @@ <h1>Flight Example</h1>
9088
<Suspense fallback="...">
9189
<h1>{model.title}</h1>
9290
</Suspense>
93-
<div dangerouslySetInnerHTML={model.content} />
91+
{model.content}
9492
</div>;
9593
}
9694

fixtures/flight/server/handler.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@ function HTML() {
2020
module.exports = function(req, res) {
2121
res.setHeader('Access-Control-Allow-Origin', '*');
2222
let model = {
23-
content: {
24-
__html: <HTML />,
25-
},
23+
content: <HTML />,
2624
};
2725
ReactFlightDOMServer.pipeToNodeWritable(model, res);
2826
};

fixtures/flight/src/App.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, {Suspense} from 'react';
22

33
function Content({data}) {
4-
return <p dangerouslySetInnerHTML={data.model.content} />;
4+
return data.model.content;
55
}
66

77
function App({data}) {

packages/legacy-events/ReactSyntheticEventType.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,7 @@ export type ReactSyntheticEvent = {|
3131
nativeEventTarget: EventTarget,
3232
) => ReactSyntheticEvent,
3333
isPersistent: () => boolean,
34+
_dispatchInstances: null | Array<Fiber>,
35+
_dispatchListeners: null | Array<Function>,
36+
_targetInst: null | Fiber,
3437
|};

packages/legacy-events/SyntheticEvent.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ function SyntheticEvent(
7676
this.dispatchConfig = dispatchConfig;
7777
this._targetInst = targetInst;
7878
this.nativeEvent = nativeEvent;
79+
this._dispatchListeners = null;
80+
this._dispatchInstances = null;
7981

8082
const Interface = this.constructor.Interface;
8183
for (const propName in Interface) {

packages/react-client/flight.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@
77
* @flow
88
*/
99

10-
export * from './src/ReactFlightClient';
10+
export * from './src/ReactFlightClientStream';

packages/react-client/src/ReactFlightClient.js

Lines changed: 100 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,21 @@
77
* @flow
88
*/
99

10-
import type {Source, StringDecoder} from './ReactFlightClientHostConfig';
11-
12-
import {
13-
supportsBinaryStreams,
14-
createStringDecoder,
15-
readPartialStringChunk,
16-
readFinalStringChunk,
17-
} from './ReactFlightClientHostConfig';
10+
import {REACT_ELEMENT_TYPE} from 'shared/ReactSymbols';
1811

1912
export type ReactModelRoot<T> = {|
2013
model: T,
2114
|};
2215

23-
type JSONValue =
16+
export type JSONValue =
2417
| number
2518
| null
2619
| boolean
2720
| string
28-
| {[key: string]: JSONValue, ...};
21+
| {[key: string]: JSONValue}
22+
| Array<JSONValue>;
23+
24+
const isArray = Array.isArray;
2925

3026
const PENDING = 0;
3127
const RESOLVED = 1;
@@ -48,39 +44,23 @@ type ErroredChunk = {|
4844
|};
4945
type Chunk = PendingChunk | ResolvedChunk | ErroredChunk;
5046

51-
type OpaqueResponseWithoutDecoder = {
52-
source: Source,
47+
export type Response = {
5348
partialRow: string,
5449
modelRoot: ReactModelRoot<any>,
5550
chunks: Map<number, Chunk>,
56-
fromJSON: (key: string, value: JSONValue) => any,
57-
...
58-
};
59-
60-
type OpaqueResponse = OpaqueResponseWithoutDecoder & {
61-
stringDecoder: StringDecoder,
62-
...
6351
};
6452

65-
export function createResponse(source: Source): OpaqueResponse {
53+
export function createResponse(): Response {
6654
let modelRoot: ReactModelRoot<any> = ({}: any);
6755
let rootChunk: Chunk = createPendingChunk();
6856
definePendingProperty(modelRoot, 'model', rootChunk);
6957
let chunks: Map<number, Chunk> = new Map();
7058
chunks.set(0, rootChunk);
71-
72-
let response: OpaqueResponse = (({
73-
source,
59+
let response = {
7460
partialRow: '',
7561
modelRoot,
7662
chunks: chunks,
77-
fromJSON: function(key, value) {
78-
return parseFromJSON(response, this, key, value);
79-
},
80-
}: OpaqueResponseWithoutDecoder): any);
81-
if (supportsBinaryStreams) {
82-
response.stringDecoder = createStringDecoder();
83-
}
63+
};
8464
return response;
8565
}
8666

@@ -138,10 +118,7 @@ function resolveChunk(chunk: Chunk, value: mixed): void {
138118

139119
// Report that any missing chunks in the model is now going to throw this
140120
// error upon read. Also notify any pending promises.
141-
export function reportGlobalError(
142-
response: OpaqueResponse,
143-
error: Error,
144-
): void {
121+
export function reportGlobalError(response: Response, error: Error): void {
145122
response.chunks.forEach(chunk => {
146123
// If this chunk was already resolved or errored, it won't
147124
// trigger an error but if it wasn't then we need to
@@ -168,39 +145,91 @@ function definePendingProperty(
168145
});
169146
}
170147

171-
function parseFromJSON(
172-
response: OpaqueResponse,
148+
function createElement(type, key, props): React$Element<any> {
149+
const element: any = {
150+
// This tag allows us to uniquely identify this as a React Element
151+
$$typeof: REACT_ELEMENT_TYPE,
152+
153+
// Built-in properties that belong on the element
154+
type: type,
155+
key: key,
156+
ref: null,
157+
props: props,
158+
159+
// Record the component responsible for creating this element.
160+
_owner: null,
161+
};
162+
if (__DEV__) {
163+
// We don't really need to add any of these but keeping them for good measure.
164+
// Unfortunately, _store is enumerable in jest matchers so for equality to
165+
// work, I need to keep it or make _store non-enumerable in the other file.
166+
element._store = {};
167+
Object.defineProperty(element._store, 'validated', {
168+
configurable: false,
169+
enumerable: false,
170+
writable: true,
171+
value: true, // This element has already been validated on the server.
172+
});
173+
Object.defineProperty(element, '_self', {
174+
configurable: false,
175+
enumerable: false,
176+
writable: false,
177+
value: null,
178+
});
179+
Object.defineProperty(element, '_source', {
180+
configurable: false,
181+
enumerable: false,
182+
writable: false,
183+
value: null,
184+
});
185+
}
186+
return element;
187+
}
188+
189+
export function parseModelFromJSON(
190+
response: Response,
173191
targetObj: Object,
174192
key: string,
175193
value: JSONValue,
176-
): any {
177-
if (typeof value === 'string' && value[0] === '$') {
178-
if (value[1] === '$') {
179-
// This was an escaped string value.
180-
return value.substring(1);
181-
} else {
182-
let id = parseInt(value.substring(1), 16);
183-
let chunks = response.chunks;
184-
let chunk = chunks.get(id);
185-
if (!chunk) {
186-
chunk = createPendingChunk();
187-
chunks.set(id, chunk);
188-
} else if (chunk.status === RESOLVED) {
189-
return chunk.value;
194+
): mixed {
195+
if (typeof value === 'string') {
196+
if (value[0] === '$') {
197+
if (value === '$') {
198+
return REACT_ELEMENT_TYPE;
199+
} else if (value[1] === '$' || value[1] === '@') {
200+
// This was an escaped string value.
201+
return value.substring(1);
202+
} else {
203+
let id = parseInt(value.substring(1), 16);
204+
let chunks = response.chunks;
205+
let chunk = chunks.get(id);
206+
if (!chunk) {
207+
chunk = createPendingChunk();
208+
chunks.set(id, chunk);
209+
} else if (chunk.status === RESOLVED) {
210+
return chunk.value;
211+
}
212+
definePendingProperty(targetObj, key, chunk);
213+
return undefined;
190214
}
191-
definePendingProperty(targetObj, key, chunk);
192-
return undefined;
215+
}
216+
}
217+
if (isArray(value)) {
218+
let tuple: [mixed, mixed, mixed, mixed] = (value: any);
219+
if (tuple[0] === REACT_ELEMENT_TYPE) {
220+
// TODO: Consider having React just directly accept these arrays as elements.
221+
// Or even change the ReactElement type to be an array.
222+
return createElement(tuple[1], tuple[2], tuple[3]);
193223
}
194224
}
195225
return value;
196226
}
197227

198-
function resolveJSONRow(
199-
response: OpaqueResponse,
228+
export function resolveModelChunk<T>(
229+
response: Response,
200230
id: number,
201-
json: string,
231+
model: T,
202232
): void {
203-
let model = JSON.parse(json, response.fromJSON);
204233
let chunks = response.chunks;
205234
let chunk = chunks.get(id);
206235
if (!chunk) {
@@ -210,88 +239,31 @@ function resolveJSONRow(
210239
}
211240
}
212241

213-
function processFullRow(response: OpaqueResponse, row: string): void {
214-
if (row === '') {
215-
return;
216-
}
217-
let tag = row[0];
218-
switch (tag) {
219-
case 'J': {
220-
let colon = row.indexOf(':', 1);
221-
let id = parseInt(row.substring(1, colon), 16);
222-
let json = row.substring(colon + 1);
223-
resolveJSONRow(response, id, json);
224-
return;
225-
}
226-
case 'E': {
227-
let colon = row.indexOf(':', 1);
228-
let id = parseInt(row.substring(1, colon), 16);
229-
let json = row.substring(colon + 1);
230-
let errorInfo = JSON.parse(json);
231-
let error = new Error(errorInfo.message);
232-
error.stack = errorInfo.stack;
233-
let chunks = response.chunks;
234-
let chunk = chunks.get(id);
235-
if (!chunk) {
236-
chunks.set(id, createErrorChunk(error));
237-
} else {
238-
triggerErrorOnChunk(chunk, error);
239-
}
240-
return;
241-
}
242-
default: {
243-
// Assume this is the root model.
244-
resolveJSONRow(response, 0, row);
245-
return;
246-
}
247-
}
248-
}
249-
250-
export function processStringChunk(
251-
response: OpaqueResponse,
252-
chunk: string,
253-
offset: number,
254-
): void {
255-
let linebreak = chunk.indexOf('\n', offset);
256-
while (linebreak > -1) {
257-
let fullrow = response.partialRow + chunk.substring(offset, linebreak);
258-
processFullRow(response, fullrow);
259-
response.partialRow = '';
260-
offset = linebreak + 1;
261-
linebreak = chunk.indexOf('\n', offset);
262-
}
263-
response.partialRow += chunk.substring(offset);
264-
}
265-
266-
export function processBinaryChunk(
267-
response: OpaqueResponse,
268-
chunk: Uint8Array,
242+
export function resolveErrorChunk(
243+
response: Response,
244+
id: number,
245+
message: string,
246+
stack: string,
269247
): void {
270-
if (!supportsBinaryStreams) {
271-
throw new Error("This environment don't support binary chunks.");
272-
}
273-
let stringDecoder = response.stringDecoder;
274-
let linebreak = chunk.indexOf(10); // newline
275-
while (linebreak > -1) {
276-
let fullrow =
277-
response.partialRow +
278-
readFinalStringChunk(stringDecoder, chunk.subarray(0, linebreak));
279-
processFullRow(response, fullrow);
280-
response.partialRow = '';
281-
chunk = chunk.subarray(linebreak + 1);
282-
linebreak = chunk.indexOf(10); // newline
248+
let error = new Error(message);
249+
error.stack = stack;
250+
let chunks = response.chunks;
251+
let chunk = chunks.get(id);
252+
if (!chunk) {
253+
chunks.set(id, createErrorChunk(error));
254+
} else {
255+
triggerErrorOnChunk(chunk, error);
283256
}
284-
response.partialRow += readPartialStringChunk(stringDecoder, chunk);
285257
}
286258

287-
export function complete(response: OpaqueResponse): void {
259+
export function close(response: Response): void {
288260
// In case there are any remaining unresolved chunks, they won't
289261
// be resolved now. So we need to issue an error to those.
290262
// Ideally we should be able to early bail out if we kept a
291263
// ref count of pending chunks.
292264
reportGlobalError(response, new Error('Connection closed.'));
293265
}
294266

295-
export function getModelRoot<T>(response: OpaqueResponse): ReactModelRoot<T> {
267+
export function getModelRoot<T>(response: Response): ReactModelRoot<T> {
296268
return response.modelRoot;
297269
}

packages/react-client/src/ReactFlightClientHostConfigBrowser.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
* @flow
88
*/
99

10-
export type Source = Promise<Response> | ReadableStream | XMLHttpRequest;
11-
1210
export type StringDecoder = TextDecoder;
1311

1412
export const supportsBinaryStreams = true;

0 commit comments

Comments
 (0)