Skip to content

Commit

Permalink
Change API to overrideSuspense
Browse files Browse the repository at this point in the history
This lets detect support for overriding Suspense from DevTools.
  • Loading branch information
gaearon committed Apr 3, 2019
1 parent d26d182 commit efebb67
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 41 deletions.
Expand Up @@ -17,24 +17,18 @@ describe('React hooks DevTools integration', () => {
let act;
let overrideHookState;
let overrideProps;
let suspendedFibers;
let overrideSuspense;

beforeEach(() => {
suspendedFibers = new Set();
global.__REACT_DEVTOOLS_GLOBAL_HOOK__ = {
inject: injected => {
overrideHookState = injected.overrideHookState;
overrideProps = injected.overrideProps;
overrideSuspense = injected.overrideSuspense;
},
supportsFiber: true,
onCommitFiberRoot: () => {},
onCommitFiberUnmount: () => {},
shouldSuspendFiber(rendererId, fiber) {
return (
suspendedFibers.has(fiber) ||
(fiber.alternate && suspendedFibers.has(fiber.alternate))
);
},
};

jest.resetModules();
Expand Down Expand Up @@ -184,40 +178,56 @@ describe('React hooks DevTools integration', () => {
}
});

it('should support triggering suspense in DEV', () => {
it('should support overriding suspense', () => {
if (__DEV__) {
// Lock the first render
overrideSuspense(() => true);
}

function MyComponent() {
return 'Done';
}

const renderer = ReactTestRenderer.create(
<React.Suspense fallback={'Loading'}>
<MyComponent />
</React.Suspense>,
<div>
<React.Suspense fallback={'Loading'}>
<MyComponent />
</React.Suspense>
</div>,
);
expect(renderer.toJSON()).toEqual('Done');

const fiber = renderer.root._currentFiber().return;
const fiber = renderer.root._currentFiber().child;
if (__DEV__) {
// Mark as loading
suspendedFibers.add(fiber);
// First render was locked
expect(renderer.toJSON().children).toEqual(['Loading']);
overrideProps(fiber, [], null); // Re-render
expect(renderer.toJSON()).toEqual('Loading');
expect(renderer.toJSON().children).toEqual(['Loading']);
// Release the lock
overrideSuspense(() => false);

overrideProps(fiber, [], null); // Re-render
expect(renderer.toJSON()).toEqual('Loading');
expect(renderer.toJSON().children).toEqual(['Done']);
overrideProps(fiber, [], null); // Re-render
expect(renderer.toJSON().children).toEqual(['Done']);

// Mark as done
suspendedFibers.delete(fiber);
// Lock again
overrideSuspense(() => true);
overrideProps(fiber, [], null); // Re-render
expect(renderer.toJSON()).toEqual('Done');
expect(renderer.toJSON().children).toEqual(['Loading']);

// Release the lock again
overrideSuspense(() => false);
overrideProps(fiber, [], null); // Re-render
expect(renderer.toJSON()).toEqual('Done');
expect(renderer.toJSON().children).toEqual(['Done']);

// Mark as loading again
suspendedFibers.add(fiber);
// Ensure it checks specific fibers.
overrideSuspense(f => f === fiber || f === fiber.alternate);
overrideProps(fiber, [], null); // Re-render
expect(renderer.toJSON().children).toEqual(['Loading']);
overrideSuspense(f => f !== fiber && f !== fiber.alternate);
overrideProps(fiber, [], null); // Re-render
expect(renderer.toJSON()).toEqual('Loading');
expect(renderer.toJSON().children).toEqual(['Done']);
} else {
expect(renderer.toJSON().children).toEqual(['Done']);
}
});
});
2 changes: 1 addition & 1 deletion packages/react-reconciler/src/ReactFiberBeginWork.js
Expand Up @@ -77,7 +77,6 @@ import {
cloneChildFibers,
} from './ReactChildFiber';
import {processUpdateQueue} from './ReactUpdateQueue';
import {shouldSuspend} from './ReactFiberDevToolsHook';
import {
NoWork,
Never,
Expand All @@ -97,6 +96,7 @@ import {
registerSuspenseInstanceRetry,
} from './ReactFiberHostConfig';
import type {SuspenseInstance} from './ReactFiberHostConfig';
import {shouldSuspend} from './ReactFiberReconciler';
import {
pushHostContext,
pushHostContainer,
Expand Down
14 changes: 0 additions & 14 deletions packages/react-reconciler/src/ReactFiberDevToolsHook.js
Expand Up @@ -16,9 +16,6 @@ declare var __REACT_DEVTOOLS_GLOBAL_HOOK__: Object | void;

let onCommitFiberRoot = null;
let onCommitFiberUnmount = null;
let shouldSuspendFiber = function() {
return false;
};
let hasLoggedError = false;

function catchErrors(fn) {
Expand Down Expand Up @@ -74,13 +71,6 @@ export function injectInternals(internals: Object): boolean {
onCommitFiberUnmount = catchErrors(fiber =>
hook.onCommitFiberUnmount(rendererID, fiber),
);
if (__DEV__) {
if (hook.shouldSuspendFiber) {
shouldSuspendFiber = catchErrors(fiber =>
hook.shouldSuspendFiber(rendererID, fiber),
);
}
}
} catch (err) {
// Catch all errors because it is unsafe to throw during initialization.
if (__DEV__) {
Expand All @@ -106,7 +96,3 @@ export function onCommitUnmount(fiber: Fiber) {
onCommitFiberUnmount(fiber);
}
}

export function shouldSuspend(fiber: Fiber) {
return shouldSuspendFiber(fiber);
}
12 changes: 12 additions & 0 deletions packages/react-reconciler/src/ReactFiberReconciler.js
Expand Up @@ -340,8 +340,15 @@ export function findHostInstanceWithNoPortals(
return hostFiber.stateNode;
}

let shouldSuspendImpl = fiber => false;

export function shouldSuspend(fiber: Fiber): boolean {
return shouldSuspendImpl(fiber);
}

let overrideHookState = null;
let overrideProps = null;
let overrideSuspense = null;

if (__DEV__) {
const copyWithSetImpl = (
Expand Down Expand Up @@ -413,6 +420,10 @@ if (__DEV__) {
}
scheduleWork(fiber, Sync);
};

overrideSuspense = (newShouldSuspendImpl: Fiber => boolean) => {
shouldSuspendImpl = newShouldSuspendImpl;
};
}

export function injectIntoDevTools(devToolsConfig: DevToolsConfig): boolean {
Expand All @@ -423,6 +434,7 @@ export function injectIntoDevTools(devToolsConfig: DevToolsConfig): boolean {
...devToolsConfig,
overrideHookState,
overrideProps,
overrideSuspense,
currentDispatcherRef: ReactCurrentDispatcher,
findHostInstanceByFiber(fiber: Fiber): Instance | TextInstance | null {
const hostFiber = findCurrentHostFiber(fiber);
Expand Down

0 comments on commit efebb67

Please sign in to comment.