@samitouri / QOS-React / commits / 933b64710a

Disable hook update callback (2nd arg to setState/dispatch)

I put the feature behind a feature flag, along with a warning, so we can phase it out in www.

Andrew Clark committed Oct 20, 2018 at 15:01 UTC 933b64710a48b2f86f71b1507901038025e79e3f
11 files changed +75 -15
packages/react-reconciler/src/ReactFiberHooks.js
+16
@@ -37,6 +37,8 @@ import {
37 } from './ReactFiberScheduler';
38
39 import invariant from 'shared/invariant';
40 +import warningWithoutStack from 'shared/warningWithoutStack';
41 +import {enableDispatchCallback_DEPRECATED} from 'shared/ReactFeatureFlags';
42
43 type Update<S, A> = {
44 expirationTime: ExpirationTime,
@@ -680,6 +682,20 @@ function dispatchAction<S, A>(
682 action: A,
683 callback: void | null | (S => mixed),
684 ) {
685 + if (enableDispatchCallback_DEPRECATED) {
686 + if (__DEV__) {
687 + if (typeof callback === 'function') {
688 + warningWithoutStack(
689 + false,
690 + 'Update callbacks (the second argument to dispatch/setState) are ' +
691 + 'deprecated. Try useEffect instead.',
692 + );
693 + }
694 + }
695 + } else {
696 + callback = null;
697 + }
698 +
699 invariant(
700 numberOfReRenders < RE_RENDER_LIMIT,
701 'Too many re-renders. React limits the number of renders to prevent ' +
packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js
+50 -15
@@ -58,6 +58,7 @@ describe('ReactHooks', () => {
58 ReactFeatureFlags = require('shared/ReactFeatureFlags');
59 ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false;
60 ReactFeatureFlags.enableHooks = true;
61 + ReactFeatureFlags.enableDispatchCallback_DEPRECATED = true;
62 ReactFeatureFlags.enableSchedulerTracing = true;
63 React = require('react');
64 ReactNoop = require('react-noop-renderer');
@@ -241,18 +242,39 @@ describe('ReactHooks', () => {
242 ReactNoop.flush();
243 expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
244
244 - counter.current.updateCount(7, count => {
245 - ReactNoop.yield(`Did update count`);
246 - });
245 + expect(() => {
246 + counter.current.updateCount(7, count => {
247 + ReactNoop.yield(`Did update count`);
248 + });
249 + }).toWarnDev(
250 + 'Warning: Update callbacks (the second argument to ' +
251 + 'dispatch/setState) are deprecated. Try useEffect instead.',
252 + {withoutStack: true},
253 + );
254 +
255 expect(ReactNoop.flush()).toEqual(['Count: 7', 'Did update count']);
256
257 // Update twice in the same batch
250 - counter.current.updateCount(1, () => {
251 - ReactNoop.yield(`Did update count (first callback)`);
252 - });
253 - counter.current.updateCount(2, () => {
254 - ReactNoop.yield(`Did update count (second callback)`);
255 - });
258 + expect(() => {
259 + counter.current.updateCount(1, () => {
260 + ReactNoop.yield(`Did update count (first callback)`);
261 + });
262 + }).toWarnDev(
263 + 'Warning: Update callbacks (the second argument to ' +
264 + 'dispatch/setState) are deprecated. Try useEffect instead.',
265 + {withoutStack: true},
266 + );
267 +
268 + expect(() => {
269 + counter.current.updateCount(2, () => {
270 + ReactNoop.yield(`Did update count (second callback)`);
271 + });
272 + }).toWarnDev(
273 + 'Warning: Update callbacks (the second argument to ' +
274 + 'dispatch/setState) are deprecated. Try useEffect instead.',
275 + {withoutStack: true},
276 + );
277 +
278 expect(ReactNoop.flush()).toEqual([
279 // Component only renders once
280 'Count: 2',
@@ -273,14 +295,27 @@ describe('ReactHooks', () => {
295 ReactNoop.flush();
296 expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
297
276 - counter.current.updateCount(1, count => {
277 - ReactNoop.yield(`Did update count (low pri)`);
278 - });
279 - ReactNoop.flushSync(() => {
280 - counter.current.updateCount(2, count => {
281 - ReactNoop.yield(`Did update count (high pri)`);
298 + expect(() => {
299 + counter.current.updateCount(1, count => {
300 + ReactNoop.yield(`Did update count (low pri)`);
301 });
302 + }).toWarnDev(
303 + 'Warning: Update callbacks (the second argument to ' +
304 + 'dispatch/setState) are deprecated. Try useEffect instead.',
305 + {withoutStack: true},
306 + );
307 + ReactNoop.flushSync(() => {
308 + expect(() => {
309 + counter.current.updateCount(2, count => {
310 + ReactNoop.yield(`Did update count (high pri)`);
311 + });
312 + }).toWarnDev(
313 + 'Warning: Update callbacks (the second argument to ' +
314 + 'dispatch/setState) are deprecated. Try useEffect instead.',
315 + {withoutStack: true},
316 + );
317 });
318 +
319 expect(ReactNoop.clearYields()).toEqual([
320 'Count: 2',
321 'Did update count (high pri)',
packages/shared/ReactFeatureFlags.js
+1
@@ -10,6 +10,7 @@
10 export const enableUserTimingAPI = __DEV__;
11
12 export const enableHooks = false;
13 +export const enableDispatchCallback_DEPRECATED = false;
14 // Helps identify side effects in begin-phase lifecycle hooks and setState reducers:
15 export const debugRenderPhaseSideEffects = false;
16
packages/shared/forks/ReactFeatureFlags.native-fabric-fb.js
+1
@@ -16,6 +16,7 @@ export const debugRenderPhaseSideEffects = false;
16 export const debugRenderPhaseSideEffectsForStrictMode = false;
17 export const enableUserTimingAPI = __DEV__;
18 export const enableHooks = false;
19 +export const enableDispatchCallback_DEPRECATED = false;
20 export const warnAboutDeprecatedLifecycles = false;
21 export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__;
22 export const enableProfilerTimer = __PROFILE__;
packages/shared/forks/ReactFeatureFlags.native-fabric-oss.js
+1
@@ -16,6 +16,7 @@ export const debugRenderPhaseSideEffects = false;
16 export const debugRenderPhaseSideEffectsForStrictMode = false;
17 export const enableUserTimingAPI = __DEV__;
18 export const enableHooks = false;
19 +export const enableDispatchCallback_DEPRECATED = false;
20 export const warnAboutDeprecatedLifecycles = false;
21 export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__;
22 export const enableProfilerTimer = __PROFILE__;
packages/shared/forks/ReactFeatureFlags.native-fb.js
+1
@@ -15,6 +15,7 @@ import typeof * as FeatureFlagsShimType from './ReactFeatureFlags.native-fb';
15 // Re-export dynamic flags from the fbsource version.
16 export const {
17 enableHooks,
18 + enableDispatchCallback_DEPRECATED,
19 debugRenderPhaseSideEffects,
20 debugRenderPhaseSideEffectsForStrictMode,
21 warnAboutDeprecatedLifecycles,
packages/shared/forks/ReactFeatureFlags.native-oss.js
+1
@@ -15,6 +15,7 @@ import typeof * as FeatureFlagsShimType from './ReactFeatureFlags.native-oss';
15 export const debugRenderPhaseSideEffects = false;
16 export const debugRenderPhaseSideEffectsForStrictMode = false;
17 export const enableHooks = false;
18 +export const enableDispatchCallback_DEPRECATED = false;
19 export const enableUserTimingAPI = __DEV__;
20 export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__;
21 export const warnAboutDeprecatedLifecycles = false;
packages/shared/forks/ReactFeatureFlags.persistent.js
+1
@@ -16,6 +16,7 @@ export const debugRenderPhaseSideEffects = false;
16 export const debugRenderPhaseSideEffectsForStrictMode = false;
17 export const enableUserTimingAPI = __DEV__;
18 export const enableHooks = false;
19 +export const enableDispatchCallback_DEPRECATED = false;
20 export const warnAboutDeprecatedLifecycles = false;
21 export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__;
22 export const enableProfilerTimer = __PROFILE__;
packages/shared/forks/ReactFeatureFlags.test-renderer.js
+1
@@ -16,6 +16,7 @@ export const debugRenderPhaseSideEffects = false;
16 export const debugRenderPhaseSideEffectsForStrictMode = false;
17 export const enableUserTimingAPI = __DEV__;
18 export const enableHooks = false;
19 +export const enableDispatchCallback_DEPRECATED = false;
20 export const warnAboutDeprecatedLifecycles = false;
21 export const replayFailedUnitOfWorkWithInvokeGuardedCallback = false;
22 export const enableProfilerTimer = false;
packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
+1
@@ -16,6 +16,7 @@ export const debugRenderPhaseSideEffects = false;
16 export const debugRenderPhaseSideEffectsForStrictMode = false;
17 export const enableUserTimingAPI = __DEV__;
18 export const enableHooks = false;
19 +export const enableDispatchCallback_DEPRECATED = false;
20 export const warnAboutDeprecatedLifecycles = false;
21 export const replayFailedUnitOfWorkWithInvokeGuardedCallback = false;
22 export const enableProfilerTimer = false;
packages/shared/forks/ReactFeatureFlags.www.js
+1
@@ -18,6 +18,7 @@ export const {
18 replayFailedUnitOfWorkWithInvokeGuardedCallback,
19 warnAboutDeprecatedLifecycles,
20 disableInputAttributeSyncing,
21 + enableDispatchCallback_DEPRECATED,
22 } = require('ReactFeatureFlags');
23
24 // The rest of the flags are static for better dead code elimination.