diff --git a/packages/react-debug-tools/src/__tests__/ReactDevToolsHooksIntegration-test.js b/packages/react-debug-tools/src/__tests__/ReactDevToolsHooksIntegration-test.js index 2b8087274dde..0d8e32ba06c7 100644 --- a/packages/react-debug-tools/src/__tests__/ReactDevToolsHooksIntegration-test.js +++ b/packages/react-debug-tools/src/__tests__/ReactDevToolsHooksIntegration-test.js @@ -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(); @@ -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( - - - , +
+ + + +
, ); - 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']); } }); }); diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js index 01b60efffe3a..2832021950f6 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.js @@ -77,7 +77,6 @@ import { cloneChildFibers, } from './ReactChildFiber'; import {processUpdateQueue} from './ReactUpdateQueue'; -import {shouldSuspend} from './ReactFiberDevToolsHook'; import { NoWork, Never, @@ -97,6 +96,7 @@ import { registerSuspenseInstanceRetry, } from './ReactFiberHostConfig'; import type {SuspenseInstance} from './ReactFiberHostConfig'; +import {shouldSuspend} from './ReactFiberReconciler'; import { pushHostContext, pushHostContainer, diff --git a/packages/react-reconciler/src/ReactFiberDevToolsHook.js b/packages/react-reconciler/src/ReactFiberDevToolsHook.js index ba8432cb269b..f7bebce841d5 100644 --- a/packages/react-reconciler/src/ReactFiberDevToolsHook.js +++ b/packages/react-reconciler/src/ReactFiberDevToolsHook.js @@ -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) { @@ -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__) { @@ -106,7 +96,3 @@ export function onCommitUnmount(fiber: Fiber) { onCommitFiberUnmount(fiber); } } - -export function shouldSuspend(fiber: Fiber) { - return shouldSuspendFiber(fiber); -} diff --git a/packages/react-reconciler/src/ReactFiberReconciler.js b/packages/react-reconciler/src/ReactFiberReconciler.js index a01df581faa5..b985392e81c0 100644 --- a/packages/react-reconciler/src/ReactFiberReconciler.js +++ b/packages/react-reconciler/src/ReactFiberReconciler.js @@ -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 = ( @@ -413,6 +420,10 @@ if (__DEV__) { } scheduleWork(fiber, Sync); }; + + overrideSuspense = (newShouldSuspendImpl: Fiber => boolean) => { + shouldSuspendImpl = newShouldSuspendImpl; + }; } export function injectIntoDevTools(devToolsConfig: DevToolsConfig): boolean { @@ -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);