Don't warn if an unmounted component is pinged (#14158)
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
Andrew Clark committed
Nov 8, 2018 at 17:24 UTC
7fd1661f80868c6006388647bd0104f5f4f3f320
2 files changed
+88
-43
packages/react-reconciler/src/ReactFiberScheduler.js
+40
-43
@@ -1747,6 +1747,46 @@ function scheduleWorkToRoot(fiber: Fiber, expirationTime): FiberRoot | null {
1747
}
1748
}
1749
1750
+ if (enableSchedulerTracing) {
1751
+ if (root !== null) {
1752
+ const interactions = __interactionsRef.current;
1753
+ if (interactions.size > 0) {
1754
+ const pendingInteractionMap = root.pendingInteractionMap;
1755
+ const pendingInteractions = pendingInteractionMap.get(expirationTime);
1756
+ if (pendingInteractions != null) {
1757
+ interactions.forEach(interaction => {
1758
+ if (!pendingInteractions.has(interaction)) {
1759
+ // Update the pending async work count for previously unscheduled interaction.
1760
+ interaction.__count++;
1761
+ }
1762
+
1763
+ pendingInteractions.add(interaction);
1764
+ });
1765
+ } else {
1766
+ pendingInteractionMap.set(expirationTime, new Set(interactions));
1767
+
1768
+ // Update the pending async work count for the current interactions.
1769
+ interactions.forEach(interaction => {
1770
+ interaction.__count++;
1771
+ });
1772
+ }
1773
+
1774
+ const subscriber = __subscriberRef.current;
1775
+ if (subscriber !== null) {
1776
+ const threadID = computeThreadID(
1777
+ expirationTime,
1778
+ root.interactionThreadID,
1779
+ );
1780
+ subscriber.onWorkScheduled(interactions, threadID);
1781
+ }
1782
+ }
1783
+ }
1784
+ }
1785
+ return root;
1786
+}
1787
+
1788
+function scheduleWork(fiber: Fiber, expirationTime: ExpirationTime) {
1789
+ const root = scheduleWorkToRoot(fiber, expirationTime);
1790
if (root === null) {
1791
if (__DEV__) {
1792
switch (fiber.tag) {
@@ -1761,49 +1801,6 @@ function scheduleWorkToRoot(fiber: Fiber, expirationTime): FiberRoot | null {
1801
break;
1802
}
1803
}
1764
- return null;
1765
- }
1766
-
1767
- if (enableSchedulerTracing) {
1768
- const interactions = __interactionsRef.current;
1769
- if (interactions.size > 0) {
1770
- const pendingInteractionMap = root.pendingInteractionMap;
1771
- const pendingInteractions = pendingInteractionMap.get(expirationTime);
1772
- if (pendingInteractions != null) {
1773
- interactions.forEach(interaction => {
1774
- if (!pendingInteractions.has(interaction)) {
1775
- // Update the pending async work count for previously unscheduled interaction.
1776
- interaction.__count++;
1777
- }
1778
-
1779
- pendingInteractions.add(interaction);
1780
- });
1781
- } else {
1782
- pendingInteractionMap.set(expirationTime, new Set(interactions));
1783
-
1784
- // Update the pending async work count for the current interactions.
1785
- interactions.forEach(interaction => {
1786
- interaction.__count++;
1787
- });
1788
- }
1789
-
1790
- const subscriber = __subscriberRef.current;
1791
- if (subscriber !== null) {
1792
- const threadID = computeThreadID(
1793
- expirationTime,
1794
- root.interactionThreadID,
1795
- );
1796
- subscriber.onWorkScheduled(interactions, threadID);
1797
- }
1798
- }
1799
- }
1800
-
1801
- return root;
1802
-}
1803
-
1804
-function scheduleWork(fiber: Fiber, expirationTime: ExpirationTime) {
1805
- const root = scheduleWorkToRoot(fiber, expirationTime);
1806
- if (root === null) {
1804
return;
1805
}
1806
packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js
+48
@@ -838,5 +838,53 @@ describe('ReactSuspense', () => {
838
]);
839
expect(root).toMatchRenderedOutput('Tab: 2 + sibling');
840
});
841
+
842
+ it('does not warn if an mounted component is pinged', () => {
843
+ const {useState} = React;
844
+
845
+ const root = ReactTestRenderer.create(null);
846
+
847
+ let setStep;
848
+ function UpdatingText({text, ms}) {
849
+ const [step, _setStep] = useState(0);
850
+ setStep = _setStep;
851
+ const fullText = `${text}:${step}`;
852
+ try {
853
+ TextResource.read([fullText, ms]);
854
+ ReactTestRenderer.unstable_yield(fullText);
855
+ return fullText;
856
+ } catch (promise) {
857
+ if (typeof promise.then === 'function') {
858
+ ReactTestRenderer.unstable_yield(`Suspend! [${fullText}]`);
859
+ } else {
860
+ ReactTestRenderer.unstable_yield(`Error! [${fullText}]`);
861
+ }
862
+ throw promise;
863
+ }
864
+ }
865
+
866
+ root.update(
867
+ <Suspense fallback={<Text text="Loading..." />}>
868
+ <UpdatingText text="A" ms={1000} />
869
+ </Suspense>,
870
+ );
871
+
872
+ expect(ReactTestRenderer).toHaveYielded(['Suspend! [A:0]', 'Loading...']);
873
+ jest.advanceTimersByTime(1000);
874
+ expect(ReactTestRenderer).toHaveYielded([
875
+ 'Promise resolved [A:0]',
876
+ 'A:0',
877
+ ]);
878
+ expect(root).toMatchRenderedOutput('A:0');
879
+
880
+ setStep(1);
881
+ expect(ReactTestRenderer).toHaveYielded(['Suspend! [A:1]', 'Loading...']);
882
+ expect(root).toMatchRenderedOutput('Loading...');
883
+
884
+ root.update(null);
885
+ expect(root).toFlushWithoutYielding();
886
+
887
+ jest.advanceTimersByTime(1000);
888
+ });
889
});
890
});