mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Update
[ghstack-poisoned]
This commit is contained in:
+16
-1
@@ -185,7 +185,7 @@ export function processReply(
|
||||
temporaryReferences: void | TemporaryReferenceSet,
|
||||
resolve: (string | FormData) => void,
|
||||
reject: (error: mixed) => void,
|
||||
): void {
|
||||
): (reason: mixed) => void {
|
||||
let nextPartId = 1;
|
||||
let pendingParts = 0;
|
||||
let formData: null | FormData = null;
|
||||
@@ -841,6 +841,19 @@ export function processReply(
|
||||
return JSON.stringify(model, resolveToJSON);
|
||||
}
|
||||
|
||||
function abort(reason: mixed): void {
|
||||
if (pendingParts > 0) {
|
||||
pendingParts = 0; // Don't resolve again later.
|
||||
// Resolve with what we have so far, which may have holes at this point.
|
||||
// They'll error when the stream completes on the server.
|
||||
if (formData === null) {
|
||||
resolve(json);
|
||||
} else {
|
||||
resolve(formData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const json = serializeModel(root, 0);
|
||||
|
||||
if (formData === null) {
|
||||
@@ -854,6 +867,8 @@ export function processReply(
|
||||
resolve(formData);
|
||||
}
|
||||
}
|
||||
|
||||
return abort;
|
||||
}
|
||||
|
||||
const boundCache: WeakMap<
|
||||
|
||||
+12
-17
@@ -112,31 +112,32 @@ export interface INativeMethods {
|
||||
measure(callback: MeasureOnSuccessCallback): void;
|
||||
measureInWindow(callback: MeasureInWindowOnSuccessCallback): void;
|
||||
measureLayout(
|
||||
relativeToNativeNode: number | ElementRef<HostComponent<mixed>>,
|
||||
relativeToNativeNode: number | HostInstance,
|
||||
onSuccess: MeasureLayoutOnSuccessCallback,
|
||||
onFail?: () => void,
|
||||
): void;
|
||||
setNativeProps(nativeProps: {...}): void;
|
||||
}
|
||||
|
||||
export type NativeMethods = $ReadOnly<{|
|
||||
export type NativeMethods = $ReadOnly<{
|
||||
blur(): void,
|
||||
focus(): void,
|
||||
measure(callback: MeasureOnSuccessCallback): void,
|
||||
measureInWindow(callback: MeasureInWindowOnSuccessCallback): void,
|
||||
measureLayout(
|
||||
relativeToNativeNode: number | ElementRef<HostComponent<mixed>>,
|
||||
relativeToNativeNode: number | HostInstance,
|
||||
onSuccess: MeasureLayoutOnSuccessCallback,
|
||||
onFail?: () => void,
|
||||
): void,
|
||||
setNativeProps(nativeProps: {...}): void,
|
||||
|}>;
|
||||
}>;
|
||||
|
||||
// This validates that INativeMethods and NativeMethods stay in sync using Flow!
|
||||
declare const ensureNativeMethodsAreSynced: NativeMethods;
|
||||
(ensureNativeMethodsAreSynced: INativeMethods);
|
||||
|
||||
export type HostComponent<T> = AbstractComponent<T, $ReadOnly<NativeMethods>>;
|
||||
export type HostInstance = NativeMethods;
|
||||
export type HostComponent<Config> = AbstractComponent<Config, HostInstance>;
|
||||
|
||||
type SecretInternalsType = {
|
||||
computeComponentStackForErrorReporting(tag: number): string,
|
||||
@@ -209,7 +210,7 @@ export type RenderRootOptions = {
|
||||
export type ReactNativeType = {
|
||||
findHostInstance_DEPRECATED<TElementType: ElementType>(
|
||||
componentOrHandle: ?(ElementRef<TElementType> | number),
|
||||
): ?ElementRef<HostComponent<mixed>>,
|
||||
): ?HostInstance,
|
||||
findNodeHandle<TElementType: ElementType>(
|
||||
componentOrHandle: ?(ElementRef<TElementType> | number),
|
||||
): ?number,
|
||||
@@ -218,14 +219,11 @@ export type ReactNativeType = {
|
||||
child: PublicInstance | HostComponent<mixed>,
|
||||
): boolean,
|
||||
dispatchCommand(
|
||||
handle: ElementRef<HostComponent<mixed>>,
|
||||
handle: HostInstance,
|
||||
command: string,
|
||||
args: Array<mixed>,
|
||||
): void,
|
||||
sendAccessibilityEvent(
|
||||
handle: ElementRef<HostComponent<mixed>>,
|
||||
eventType: string,
|
||||
): void,
|
||||
sendAccessibilityEvent(handle: HostInstance, eventType: string): void,
|
||||
render(
|
||||
element: MixedElement,
|
||||
containerTag: number,
|
||||
@@ -247,20 +245,17 @@ type PublicTextInstance = mixed;
|
||||
export type ReactFabricType = {
|
||||
findHostInstance_DEPRECATED<TElementType: ElementType>(
|
||||
componentOrHandle: ?(ElementRef<TElementType> | number),
|
||||
): ?ElementRef<HostComponent<mixed>>,
|
||||
): ?HostInstance,
|
||||
findNodeHandle<TElementType: ElementType>(
|
||||
componentOrHandle: ?(ElementRef<TElementType> | number),
|
||||
): ?number,
|
||||
dispatchCommand(
|
||||
handle: ElementRef<HostComponent<mixed>>,
|
||||
handle: HostInstance,
|
||||
command: string,
|
||||
args: Array<mixed>,
|
||||
): void,
|
||||
isChildPublicInstance(parent: PublicInstance, child: PublicInstance): boolean,
|
||||
sendAccessibilityEvent(
|
||||
handle: ElementRef<HostComponent<mixed>>,
|
||||
eventType: string,
|
||||
): void,
|
||||
sendAccessibilityEvent(handle: HostInstance, eventType: string): void,
|
||||
render(
|
||||
element: MixedElement,
|
||||
containerTag: number,
|
||||
|
||||
@@ -121,12 +121,12 @@ function createFromFetch<T>(
|
||||
|
||||
function encodeReply(
|
||||
value: ReactServerValue,
|
||||
options?: {temporaryReferences?: TemporaryReferenceSet},
|
||||
options?: {temporaryReferences?: TemporaryReferenceSet, signal?: AbortSignal},
|
||||
): Promise<
|
||||
string | URLSearchParams | FormData,
|
||||
> /* We don't use URLSearchParams yet but maybe */ {
|
||||
return new Promise((resolve, reject) => {
|
||||
processReply(
|
||||
const abort = processReply(
|
||||
value,
|
||||
'',
|
||||
options && options.temporaryReferences
|
||||
@@ -135,6 +135,18 @@ function encodeReply(
|
||||
resolve,
|
||||
reject,
|
||||
);
|
||||
if (options && options.signal) {
|
||||
const signal = options.signal;
|
||||
if (signal.aborted) {
|
||||
abort((signal: any).reason);
|
||||
} else {
|
||||
const listener = () => {
|
||||
abort((signal: any).reason);
|
||||
signal.removeEventListener('abort', listener);
|
||||
};
|
||||
signal.addEventListener('abort', listener);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+14
-2
@@ -120,12 +120,12 @@ function createFromFetch<T>(
|
||||
|
||||
function encodeReply(
|
||||
value: ReactServerValue,
|
||||
options?: {temporaryReferences?: TemporaryReferenceSet},
|
||||
options?: {temporaryReferences?: TemporaryReferenceSet, signal?: AbortSignal},
|
||||
): Promise<
|
||||
string | URLSearchParams | FormData,
|
||||
> /* We don't use URLSearchParams yet but maybe */ {
|
||||
return new Promise((resolve, reject) => {
|
||||
processReply(
|
||||
const abort = processReply(
|
||||
value,
|
||||
'',
|
||||
options && options.temporaryReferences
|
||||
@@ -134,6 +134,18 @@ function encodeReply(
|
||||
resolve,
|
||||
reject,
|
||||
);
|
||||
if (options && options.signal) {
|
||||
const signal = options.signal;
|
||||
if (signal.aborted) {
|
||||
abort((signal: any).reason);
|
||||
} else {
|
||||
const listener = () => {
|
||||
abort((signal: any).reason);
|
||||
signal.removeEventListener('abort', listener);
|
||||
};
|
||||
signal.addEventListener('abort', listener);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+14
-2
@@ -149,12 +149,12 @@ function createFromFetch<T>(
|
||||
|
||||
function encodeReply(
|
||||
value: ReactServerValue,
|
||||
options?: {temporaryReferences?: TemporaryReferenceSet},
|
||||
options?: {temporaryReferences?: TemporaryReferenceSet, signal?: AbortSignal},
|
||||
): Promise<
|
||||
string | URLSearchParams | FormData,
|
||||
> /* We don't use URLSearchParams yet but maybe */ {
|
||||
return new Promise((resolve, reject) => {
|
||||
processReply(
|
||||
const abort = processReply(
|
||||
value,
|
||||
'',
|
||||
options && options.temporaryReferences
|
||||
@@ -163,6 +163,18 @@ function encodeReply(
|
||||
resolve,
|
||||
reject,
|
||||
);
|
||||
if (options && options.signal) {
|
||||
const signal = options.signal;
|
||||
if (signal.aborted) {
|
||||
abort((signal: any).reason);
|
||||
} else {
|
||||
const listener = () => {
|
||||
abort((signal: any).reason);
|
||||
signal.removeEventListener('abort', listener);
|
||||
};
|
||||
signal.addEventListener('abort', listener);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -618,4 +618,20 @@ describe('ReactFlightDOMReply', () => {
|
||||
const root = await ReactServerDOMServer.decodeReply(body, webpackServerMap);
|
||||
expect(root.prop.obj).toBe(root.prop);
|
||||
});
|
||||
|
||||
it('can abort an unresolved model and get the partial result', async () => {
|
||||
const promise = new Promise(r => {});
|
||||
const controller = new AbortController();
|
||||
const bodyPromise = ReactServerDOMClient.encodeReply(
|
||||
{promise: promise, hello: 'world'},
|
||||
{signal: controller.signal},
|
||||
);
|
||||
controller.abort();
|
||||
|
||||
const result = await ReactServerDOMServer.decodeReply(await bodyPromise);
|
||||
expect(result.hello).toBe('world');
|
||||
// TODO: await result.promise should reject at this point because the stream
|
||||
// has closed but that's a bug in both ReactFlightReplyServer and ReactFlightClient.
|
||||
// It just halts in this case.
|
||||
});
|
||||
});
|
||||
|
||||
+14
-2
@@ -120,12 +120,12 @@ function createFromFetch<T>(
|
||||
|
||||
function encodeReply(
|
||||
value: ReactServerValue,
|
||||
options?: {temporaryReferences?: TemporaryReferenceSet},
|
||||
options?: {temporaryReferences?: TemporaryReferenceSet, signal?: AbortSignal},
|
||||
): Promise<
|
||||
string | URLSearchParams | FormData,
|
||||
> /* We don't use URLSearchParams yet but maybe */ {
|
||||
return new Promise((resolve, reject) => {
|
||||
processReply(
|
||||
const abort = processReply(
|
||||
value,
|
||||
'',
|
||||
options && options.temporaryReferences
|
||||
@@ -134,6 +134,18 @@ function encodeReply(
|
||||
resolve,
|
||||
reject,
|
||||
);
|
||||
if (options && options.signal) {
|
||||
const signal = options.signal;
|
||||
if (signal.aborted) {
|
||||
abort((signal: any).reason);
|
||||
} else {
|
||||
const listener = () => {
|
||||
abort((signal: any).reason);
|
||||
signal.removeEventListener('abort', listener);
|
||||
};
|
||||
signal.addEventListener('abort', listener);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -149,12 +149,12 @@ function createFromFetch<T>(
|
||||
|
||||
function encodeReply(
|
||||
value: ReactServerValue,
|
||||
options?: {temporaryReferences?: TemporaryReferenceSet},
|
||||
options?: {temporaryReferences?: TemporaryReferenceSet, signal?: AbortSignal},
|
||||
): Promise<
|
||||
string | URLSearchParams | FormData,
|
||||
> /* We don't use URLSearchParams yet but maybe */ {
|
||||
return new Promise((resolve, reject) => {
|
||||
processReply(
|
||||
const abort = processReply(
|
||||
value,
|
||||
'',
|
||||
options && options.temporaryReferences
|
||||
@@ -163,6 +163,18 @@ function encodeReply(
|
||||
resolve,
|
||||
reject,
|
||||
);
|
||||
if (options && options.signal) {
|
||||
const signal = options.signal;
|
||||
if (signal.aborted) {
|
||||
abort((signal: any).reason);
|
||||
} else {
|
||||
const listener = () => {
|
||||
abort((signal: any).reason);
|
||||
signal.removeEventListener('abort', listener);
|
||||
};
|
||||
signal.addEventListener('abort', listener);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user