From c0decf3b66b894de9576e79a19cf0724bf4748d0 Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Thu, 8 Nov 2018 17:24:32 -0800 Subject: [PATCH] Don't warn if an unmounted component is pinged (#14158) * Add failing test for ping on unmounted component We had a test for this, but not outside of concurrent mode :) * Don't warn if an unmounted component is pinged --- .../src/ReactFiberScheduler.js | 83 +++++++++---------- .../__tests__/ReactSuspense-test.internal.js | 48 +++++++++++ 2 files changed, 88 insertions(+), 43 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberScheduler.js b/packages/react-reconciler/src/ReactFiberScheduler.js index d06740d25c51c..cebb87ff5a4b8 100644 --- a/packages/react-reconciler/src/ReactFiberScheduler.js +++ b/packages/react-reconciler/src/ReactFiberScheduler.js @@ -1747,6 +1747,46 @@ function scheduleWorkToRoot(fiber: Fiber, expirationTime): FiberRoot | null { } } + if (enableSchedulerTracing) { + if (root !== null) { + const interactions = __interactionsRef.current; + if (interactions.size > 0) { + const pendingInteractionMap = root.pendingInteractionMap; + const pendingInteractions = pendingInteractionMap.get(expirationTime); + if (pendingInteractions != null) { + interactions.forEach(interaction => { + if (!pendingInteractions.has(interaction)) { + // Update the pending async work count for previously unscheduled interaction. + interaction.__count++; + } + + pendingInteractions.add(interaction); + }); + } else { + pendingInteractionMap.set(expirationTime, new Set(interactions)); + + // Update the pending async work count for the current interactions. + interactions.forEach(interaction => { + interaction.__count++; + }); + } + + const subscriber = __subscriberRef.current; + if (subscriber !== null) { + const threadID = computeThreadID( + expirationTime, + root.interactionThreadID, + ); + subscriber.onWorkScheduled(interactions, threadID); + } + } + } + } + return root; +} + +function scheduleWork(fiber: Fiber, expirationTime: ExpirationTime) { + const root = scheduleWorkToRoot(fiber, expirationTime); if (root === null) { if (__DEV__) { switch (fiber.tag) { @@ -1761,49 +1801,6 @@ function scheduleWorkToRoot(fiber: Fiber, expirationTime): FiberRoot | null { break; } } - return null; - } - - if (enableSchedulerTracing) { - const interactions = __interactionsRef.current; - if (interactions.size > 0) { - const pendingInteractionMap = root.pendingInteractionMap; - const pendingInteractions = pendingInteractionMap.get(expirationTime); - if (pendingInteractions != null) { - interactions.forEach(interaction => { - if (!pendingInteractions.has(interaction)) { - // Update the pending async work count for previously unscheduled interaction. - interaction.__count++; - } - - pendingInteractions.add(interaction); - }); - } else { - pendingInteractionMap.set(expirationTime, new Set(interactions)); - - // Update the pending async work count for the current interactions. - interactions.forEach(interaction => { - interaction.__count++; - }); - } - - const subscriber = __subscriberRef.current; - if (subscriber !== null) { - const threadID = computeThreadID( - expirationTime, - root.interactionThreadID, - ); - subscriber.onWorkScheduled(interactions, threadID); - } - } - } - - return root; -} - -function scheduleWork(fiber: Fiber, expirationTime: ExpirationTime) { - const root = scheduleWorkToRoot(fiber, expirationTime); - if (root === null) { return; } diff --git a/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js b/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js index 1d987f70fd020..8647b2a5d5c61 100644 --- a/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js @@ -838,5 +838,53 @@ describe('ReactSuspense', () => { ]); expect(root).toMatchRenderedOutput('Tab: 2 + sibling'); }); + + it('does not warn if an mounted component is pinged', () => { + const {useState} = React; + + const root = ReactTestRenderer.create(null); + + let setStep; + function UpdatingText({text, ms}) { + const [step, _setStep] = useState(0); + setStep = _setStep; + const fullText = `${text}:${step}`; + try { + TextResource.read([fullText, ms]); + ReactTestRenderer.unstable_yield(fullText); + return fullText; + } catch (promise) { + if (typeof promise.then === 'function') { + ReactTestRenderer.unstable_yield(`Suspend! [${fullText}]`); + } else { + ReactTestRenderer.unstable_yield(`Error! [${fullText}]`); + } + throw promise; + } + } + + root.update( + }> + + , + ); + + expect(ReactTestRenderer).toHaveYielded(['Suspend! [A:0]', 'Loading...']); + jest.advanceTimersByTime(1000); + expect(ReactTestRenderer).toHaveYielded([ + 'Promise resolved [A:0]', + 'A:0', + ]); + expect(root).toMatchRenderedOutput('A:0'); + + setStep(1); + expect(ReactTestRenderer).toHaveYielded(['Suspend! [A:1]', 'Loading...']); + expect(root).toMatchRenderedOutput('Loading...'); + + root.update(null); + expect(root).toFlushWithoutYielding(); + + jest.advanceTimersByTime(1000); + }); }); });