diff --git a/packages/react-dom/src/server/ReactPartialRendererHooks.js b/packages/react-dom/src/server/ReactPartialRendererHooks.js index 1420f1bcc9..7c8f1784d8 100644 --- a/packages/react-dom/src/server/ReactPartialRendererHooks.js +++ b/packages/react-dom/src/server/ReactPartialRendererHooks.js @@ -12,22 +12,21 @@ import invariant from 'shared/invariant'; import warning from 'shared/warning'; type BasicStateAction = (S => S) | S; -type MaybeCallback = void | null | (S => mixed); -type Dispatch = (A, MaybeCallback) => void; +type Dispatch = A => void; -type Update = { +type Update = { action: A, - next: Update | null, + next: Update | null, }; -type UpdateQueue = { - last: Update | null, +type UpdateQueue = { + last: Update | null, dispatch: any, }; type Hook = { memoizedState: any, - queue: UpdateQueue | null, + queue: UpdateQueue | null, next: Hook | null, }; @@ -39,10 +38,7 @@ let isReRender: boolean = false; // Whether an update was scheduled during the currently executing render pass. let didScheduleRenderPhaseUpdate: boolean = false; // Lazily created map of render-phase updates -let renderPhaseUpdates: Map< - UpdateQueue, - Update, -> | null = null; +let renderPhaseUpdates: Map, Update> | null = null; // Counter to prevent infinite loops. let numberOfReRenders: number = 0; const RE_RENDER_LIMIT = 25; @@ -159,7 +155,7 @@ function basicStateReducer(state: S, action: BasicStateAction): S { export function useState( initialState: (() => S) | S, -): [S, Dispatch>] { +): [S, Dispatch>] { return useReducer( basicStateReducer, // useReducer has a special case to support lazy useState initializers @@ -171,14 +167,14 @@ export function useReducer( reducer: (S, A) => S, initialState: S, initialAction: A | void | null, -): [S, Dispatch] { +): [S, Dispatch] { currentlyRenderingComponent = resolveCurrentlyRenderingComponent(); workInProgressHook = createWorkInProgressHook(); if (isReRender) { // This is a re-render. Apply the new render phase updates to the previous // current hook. - const queue: UpdateQueue = (workInProgressHook.queue: any); - const dispatch: Dispatch = (queue.dispatch: any); + const queue: UpdateQueue = (workInProgressHook.queue: any); + const dispatch: Dispatch = (queue.dispatch: any); if (renderPhaseUpdates !== null) { // Render phase updates are stored in a map of queue -> linked list const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); @@ -211,11 +207,11 @@ export function useReducer( initialState = reducer(initialState, initialAction); } workInProgressHook.memoizedState = initialState; - const queue: UpdateQueue = (workInProgressHook.queue = { + const queue: UpdateQueue = (workInProgressHook.queue = { last: null, dispatch: null, }); - const dispatch: Dispatch = (queue.dispatch = (dispatchAction.bind( + const dispatch: Dispatch = (queue.dispatch = (dispatchAction.bind( null, currentlyRenderingComponent, queue, @@ -294,9 +290,9 @@ export function useLayoutEffect( ); } -function dispatchAction( +function dispatchAction( componentIdentity: Object, - queue: UpdateQueue, + queue: UpdateQueue, action: A, ) { invariant( @@ -310,7 +306,7 @@ function dispatchAction( // queue -> linked list of updates. After this render pass, we'll restart // and apply the stashed updates on top of the work-in-progress hook. didScheduleRenderPhaseUpdate = true; - const update: Update = { + const update: Update = { action, next: null, }; diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.js b/packages/react-reconciler/src/ReactFiberCommitWork.js index 2f76b6ff50..dfebe43da3 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.js @@ -319,21 +319,6 @@ function commitLifeCycles( case ForwardRef: case SimpleMemoComponent: { commitHookEffectList(UnmountLayout, MountLayout, finishedWork); - const newUpdateQueue: FunctionComponentUpdateQueue | null = (finishedWork.updateQueue: any); - if (newUpdateQueue !== null) { - const callbackList = newUpdateQueue.callbackList; - if (callbackList !== null) { - newUpdateQueue.callbackList = null; - for (let i = 0; i < callbackList.length; i++) { - const update = callbackList[i]; - // Assume this is non-null, since otherwise it would not be part - // of the callback list. - const callback: () => mixed = (update.callback: any); - update.callback = null; - callback(); - } - } - } break; } case ClassComponent: { diff --git a/packages/react-reconciler/src/ReactFiberHooks.js b/packages/react-reconciler/src/ReactFiberHooks.js index fecab6f5f8..d2542a1b92 100644 --- a/packages/react-reconciler/src/ReactFiberHooks.js +++ b/packages/react-reconciler/src/ReactFiberHooks.js @@ -17,7 +17,6 @@ import {readContext} from './ReactFiberNewContext'; import { Snapshot as SnapshotEffect, Update as UpdateEffect, - Callback as CallbackEffect, Passive as PassiveEffect, } from 'shared/ReactSideEffectTags'; import { @@ -38,18 +37,15 @@ import { import invariant from 'shared/invariant'; import warning from 'shared/warning'; -import warningWithoutStack from 'shared/warningWithoutStack'; -import {enableDispatchCallback_DEPRECATED} from 'shared/ReactFeatureFlags'; -type Update = { +type Update = { expirationTime: ExpirationTime, action: A, - callback: null | (S => mixed), - next: Update | null, + next: Update | null, }; -type UpdateQueue = { - last: Update | null, +type UpdateQueue = { + last: Update | null, dispatch: any, }; @@ -57,8 +53,8 @@ type Hook = { memoizedState: any, baseState: any, - baseUpdate: Update | null, - queue: UpdateQueue | null, + baseUpdate: Update | null, + queue: UpdateQueue | null, next: Hook | null, }; @@ -72,15 +68,12 @@ type Effect = { }; export type FunctionComponentUpdateQueue = { - callbackList: Array> | null, lastEffect: Effect | null, }; type BasicStateAction = (S => S) | S; -type MaybeCallback = void | null | (S => mixed); - -type Dispatch = (A, MaybeCallback) => void; +type Dispatch = A => void; // These are set right before calling the component. let renderExpirationTime: ExpirationTime = NoWork; @@ -113,10 +106,7 @@ let isReRender: boolean = false; // Whether an update was scheduled during the currently executing render pass. let didScheduleRenderPhaseUpdate: boolean = false; // Lazily created map of render-phase updates -let renderPhaseUpdates: Map< - UpdateQueue, - Update, -> | null = null; +let renderPhaseUpdates: Map, Update> | null = null; // Counter to prevent infinite loops. let numberOfReRenders: number = 0; const RE_RENDER_LIMIT = 25; @@ -313,7 +303,6 @@ function createWorkInProgressHook(): Hook { function createFunctionComponentUpdateQueue(): FunctionComponentUpdateQueue { return { - callbackList: null, lastEffect: null, }; } @@ -334,7 +323,7 @@ export function useContext( export function useState( initialState: (() => S) | S, -): [S, Dispatch>] { +): [S, Dispatch>] { return useReducer( basicStateReducer, // useReducer has a special case to support lazy useState initializers @@ -346,16 +335,16 @@ export function useReducer( reducer: (S, A) => S, initialState: S, initialAction: A | void | null, -): [S, Dispatch] { +): [S, Dispatch] { currentlyRenderingFiber = resolveCurrentlyRenderingFiber(); workInProgressHook = createWorkInProgressHook(); - let queue: UpdateQueue | null = (workInProgressHook.queue: any); + let queue: UpdateQueue | null = (workInProgressHook.queue: any); if (queue !== null) { // Already have a queue, so this is an update. if (isReRender) { // This is a re-render. Apply the new render phase updates to the previous // work-in-progress hook. - const dispatch: Dispatch = (queue.dispatch: any); + const dispatch: Dispatch = (queue.dispatch: any); if (renderPhaseUpdates !== null) { // Render phase updates are stored in a map of queue -> linked list const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); @@ -369,10 +358,6 @@ export function useReducer( // render's. const action = update.action; newState = reducer(newState, action); - const callback = update.callback; - if (callback !== null) { - pushCallback(currentlyRenderingFiber, update); - } update = update.next; } while (update !== null); @@ -439,10 +424,6 @@ export function useReducer( // Process this update. const action = update.action; newState = reducer(newState, action); - const callback = update.callback; - if (callback !== null) { - pushCallback(currentlyRenderingFiber, update); - } } prevUpdate = update; update = update.next; @@ -458,7 +439,7 @@ export function useReducer( workInProgressHook.baseState = newBaseState; } - const dispatch: Dispatch = (queue.dispatch: any); + const dispatch: Dispatch = (queue.dispatch: any); return [workInProgressHook.memoizedState, dispatch]; } @@ -476,7 +457,7 @@ export function useReducer( last: null, dispatch: null, }; - const dispatch: Dispatch = (queue.dispatch = (dispatchAction.bind( + const dispatch: Dispatch = (queue.dispatch = (dispatchAction.bind( null, currentlyRenderingFiber, queue, @@ -484,21 +465,6 @@ export function useReducer( return [workInProgressHook.memoizedState, dispatch]; } -function pushCallback(workInProgress: Fiber, update: Update): void { - if (componentUpdateQueue === null) { - componentUpdateQueue = createFunctionComponentUpdateQueue(); - componentUpdateQueue.callbackList = [update]; - } else { - const callbackList = componentUpdateQueue.callbackList; - if (callbackList === null) { - componentUpdateQueue.callbackList = [update]; - } else { - callbackList.push(update); - } - } - workInProgress.effectTag |= CallbackEffect; -} - function pushEffect(tag, create, destroy, inputs) { const effect: Effect = { tag, @@ -677,26 +643,7 @@ export function useMemo( return nextValue; } -function dispatchAction( - fiber: Fiber, - queue: UpdateQueue, - action: A, - callback: void | null | (S => mixed), -) { - if (enableDispatchCallback_DEPRECATED) { - if (__DEV__) { - if (typeof callback === 'function') { - warningWithoutStack( - false, - 'Update callbacks (the second argument to dispatch/setState) are ' + - 'deprecated. Try useEffect instead.', - ); - } - } - } else { - callback = null; - } - +function dispatchAction(fiber: Fiber, queue: UpdateQueue, action: A) { invariant( numberOfReRenders < RE_RENDER_LIMIT, 'Too many re-renders. React limits the number of renders to prevent ' + @@ -712,10 +659,9 @@ function dispatchAction( // queue -> linked list of updates. After this render pass, we'll restart // and apply the stashed updates on top of the work-in-progress hook. didScheduleRenderPhaseUpdate = true; - const update: Update = { + const update: Update = { expirationTime: renderExpirationTime, action, - callback: callback !== undefined ? callback : null, next: null, }; if (renderPhaseUpdates === null) { @@ -735,10 +681,9 @@ function dispatchAction( } else { const currentTime = requestCurrentTime(); const expirationTime = computeExpirationForFiber(currentTime, fiber); - const update: Update = { + const update: Update = { expirationTime, action, - callback: callback !== undefined ? callback : null, next: null, }; flushPassiveEffects(); diff --git a/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.internal.js b/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.internal.js index 62d1a6d600..b2c5cd07c0 100644 --- a/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.internal.js @@ -61,7 +61,6 @@ describe('ReactHooksWithNoopRenderer', () => { ReactFeatureFlags = require('shared/ReactFeatureFlags'); ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; ReactFeatureFlags.enableHooks = true; - ReactFeatureFlags.enableDispatchCallback_DEPRECATED = true; ReactFeatureFlags.enableSchedulerTracing = true; React = require('react'); ReactNoop = require('react-noop-renderer'); @@ -233,104 +232,6 @@ describe('ReactHooksWithNoopRenderer', () => { expect(ReactNoop.flush()).toEqual(['Total: 7']); }); - it('callbacks', () => { - function Counter(props, ref) { - const [count, updateCount] = useState(0); - useImperativeMethods(ref, () => ({updateCount})); - return ; - } - Counter = forwardRef(Counter); - const counter = React.createRef(null); - ReactNoop.render(); - ReactNoop.flush(); - expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]); - - expect(() => { - counter.current.updateCount(7, count => { - ReactNoop.yield(`Did update count`); - }); - }).toWarnDev( - 'Warning: Update callbacks (the second argument to ' + - 'dispatch/setState) are deprecated. Try useEffect instead.', - {withoutStack: true}, - ); - - expect(ReactNoop.flush()).toEqual(['Count: 7', 'Did update count']); - - // Update twice in the same batch - expect(() => { - counter.current.updateCount(1, () => { - ReactNoop.yield(`Did update count (first callback)`); - }); - }).toWarnDev( - 'Warning: Update callbacks (the second argument to ' + - 'dispatch/setState) are deprecated. Try useEffect instead.', - {withoutStack: true}, - ); - - expect(() => { - counter.current.updateCount(2, () => { - ReactNoop.yield(`Did update count (second callback)`); - }); - }).toWarnDev( - 'Warning: Update callbacks (the second argument to ' + - 'dispatch/setState) are deprecated. Try useEffect instead.', - {withoutStack: true}, - ); - - expect(ReactNoop.flush()).toEqual([ - // Component only renders once - 'Count: 2', - 'Did update count (first callback)', - 'Did update count (second callback)', - ]); - }); - - it('does not fire callbacks more than once when rebasing', () => { - function Counter(props, ref) { - const [count, updateCount] = useState(0); - useImperativeMethods(ref, () => ({updateCount})); - return ; - } - Counter = forwardRef(Counter); - const counter = React.createRef(null); - ReactNoop.render(); - ReactNoop.flush(); - expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]); - - expect(() => { - counter.current.updateCount(1, count => { - ReactNoop.yield(`Did update count (low pri)`); - }); - }).toWarnDev( - 'Warning: Update callbacks (the second argument to ' + - 'dispatch/setState) are deprecated. Try useEffect instead.', - {withoutStack: true}, - ); - ReactNoop.flushSync(() => { - expect(() => { - counter.current.updateCount(2, count => { - ReactNoop.yield(`Did update count (high pri)`); - }); - }).toWarnDev( - 'Warning: Update callbacks (the second argument to ' + - 'dispatch/setState) are deprecated. Try useEffect instead.', - {withoutStack: true}, - ); - }); - - expect(ReactNoop.clearYields()).toEqual([ - 'Count: 2', - 'Did update count (high pri)', - ]); - // The high-pri update is processed again when we render at low priority, - // but its callback should not fire again. - expect(ReactNoop.flush()).toEqual([ - 'Count: 2', - 'Did update count (low pri)', - ]); - }); - it('returns the same updater function every time', () => { let updaters = []; function Counter() { diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index e41d9c8996..028b5a8e32 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -10,7 +10,6 @@ export const enableUserTimingAPI = __DEV__; export const enableHooks = false; -export const enableDispatchCallback_DEPRECATED = false; // Helps identify side effects in begin-phase lifecycle hooks and setState reducers: export const debugRenderPhaseSideEffects = false; diff --git a/packages/shared/forks/ReactFeatureFlags.native-fabric-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fabric-fb.js index 7449853c3c..971f6bcbd3 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fabric-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fabric-fb.js @@ -16,7 +16,6 @@ export const debugRenderPhaseSideEffects = false; export const debugRenderPhaseSideEffectsForStrictMode = false; export const enableUserTimingAPI = __DEV__; export const enableHooks = false; -export const enableDispatchCallback_DEPRECATED = false; export const warnAboutDeprecatedLifecycles = false; export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__; export const enableProfilerTimer = __PROFILE__; diff --git a/packages/shared/forks/ReactFeatureFlags.native-fabric-oss.js b/packages/shared/forks/ReactFeatureFlags.native-fabric-oss.js index 05a5d9fb15..3f647674e3 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fabric-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fabric-oss.js @@ -16,7 +16,6 @@ export const debugRenderPhaseSideEffects = false; export const debugRenderPhaseSideEffectsForStrictMode = false; export const enableUserTimingAPI = __DEV__; export const enableHooks = false; -export const enableDispatchCallback_DEPRECATED = false; export const warnAboutDeprecatedLifecycles = false; export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__; export const enableProfilerTimer = __PROFILE__; diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index d9dcb280b9..6e9d290359 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -15,7 +15,6 @@ import typeof * as FeatureFlagsShimType from './ReactFeatureFlags.native-fb'; // Re-export dynamic flags from the fbsource version. export const { enableHooks, - enableDispatchCallback_DEPRECATED, debugRenderPhaseSideEffects, debugRenderPhaseSideEffectsForStrictMode, warnAboutDeprecatedLifecycles, diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index 88026e4767..96f7607431 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -15,7 +15,6 @@ import typeof * as FeatureFlagsShimType from './ReactFeatureFlags.native-oss'; export const debugRenderPhaseSideEffects = false; export const debugRenderPhaseSideEffectsForStrictMode = false; export const enableHooks = false; -export const enableDispatchCallback_DEPRECATED = false; export const enableUserTimingAPI = __DEV__; export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__; export const warnAboutDeprecatedLifecycles = false; diff --git a/packages/shared/forks/ReactFeatureFlags.persistent.js b/packages/shared/forks/ReactFeatureFlags.persistent.js index a990378314..bcb561d62b 100644 --- a/packages/shared/forks/ReactFeatureFlags.persistent.js +++ b/packages/shared/forks/ReactFeatureFlags.persistent.js @@ -16,7 +16,6 @@ export const debugRenderPhaseSideEffects = false; export const debugRenderPhaseSideEffectsForStrictMode = false; export const enableUserTimingAPI = __DEV__; export const enableHooks = false; -export const enableDispatchCallback_DEPRECATED = false; export const warnAboutDeprecatedLifecycles = false; export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__; export const enableProfilerTimer = __PROFILE__; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js index 93e5580665..9431ff5623 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js @@ -16,7 +16,6 @@ export const debugRenderPhaseSideEffects = false; export const debugRenderPhaseSideEffectsForStrictMode = false; export const enableUserTimingAPI = __DEV__; export const enableHooks = false; -export const enableDispatchCallback_DEPRECATED = false; export const warnAboutDeprecatedLifecycles = false; export const replayFailedUnitOfWorkWithInvokeGuardedCallback = false; export const enableProfilerTimer = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js index d1e14b3531..fb1c9bd817 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js @@ -16,7 +16,6 @@ export const debugRenderPhaseSideEffects = false; export const debugRenderPhaseSideEffectsForStrictMode = false; export const enableUserTimingAPI = __DEV__; export const enableHooks = false; -export const enableDispatchCallback_DEPRECATED = false; export const warnAboutDeprecatedLifecycles = false; export const replayFailedUnitOfWorkWithInvokeGuardedCallback = false; export const enableProfilerTimer = false; diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index 7bc4628a62..bf0057ef36 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -18,7 +18,6 @@ export const { replayFailedUnitOfWorkWithInvokeGuardedCallback, warnAboutDeprecatedLifecycles, disableInputAttributeSyncing, - enableDispatchCallback_DEPRECATED, } = require('ReactFeatureFlags'); // The rest of the flags are static for better dead code elimination.