From 9b972e58cb3803db1df3649f570aeeff577499de Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Wed, 10 Mar 2021 21:20:57 -0700 Subject: [PATCH] Flip tuple order of useTransition --- .../ESLintRuleExhaustiveDeps-test.js | 8 +++--- .../src/ExhaustiveDeps.js | 11 +++++--- .../react-debug-tools/src/ReactDebugHooks.js | 4 +-- .../InspectedElementErrorsAndWarningsTree.js | 4 +-- .../src/devtools/views/Components/KeyValue.js | 2 +- .../src/server/ReactPartialRendererHooks.js | 4 +-- .../src/ReactFiberHooks.new.js | 26 +++++++++---------- .../src/ReactFiberHooks.old.js | 26 +++++++++---------- .../src/ReactInternalTypes.js | 2 +- .../src/__tests__/ReactHooks-test.internal.js | 2 +- .../ReactHooksWithNoopRenderer-test.js | 9 ++----- .../ReactSuspenseWithNoopRenderer-test.js | 11 +++----- .../src/__tests__/ReactTransition-test.js | 4 +-- packages/react-server/src/ReactFizzHooks.js | 4 +-- packages/react/src/ReactHooks.js | 2 +- 15 files changed, 58 insertions(+), 61 deletions(-) diff --git a/packages/eslint-plugin-react-hooks/__tests__/ESLintRuleExhaustiveDeps-test.js b/packages/eslint-plugin-react-hooks/__tests__/ESLintRuleExhaustiveDeps-test.js index 430e78562491..bde0c1cfa35e 100644 --- a/packages/eslint-plugin-react-hooks/__tests__/ESLintRuleExhaustiveDeps-test.js +++ b/packages/eslint-plugin-react-hooks/__tests__/ESLintRuleExhaustiveDeps-test.js @@ -604,10 +604,10 @@ const tests = { const [state4, dispatch2] = React.useReducer(); const [state5, maybeSetState] = useFunnyState(); const [state6, maybeDispatch] = useFunnyReducer(); - const [startTransition1] = useTransition(); - const [startTransition2, isPending2] = useTransition(); - const [startTransition3] = React.useTransition(); - const [startTransition4, isPending4] = React.useTransition(); + const [isPending1] = useTransition(); + const [isPending2, startTransition2] = useTransition(); + const [isPending3] = React.useTransition(); + const [isPending4, startTransition4] = React.useTransition(); const mySetState = useCallback(() => {}, []); let myDispatch = useCallback(() => {}, []); diff --git a/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js b/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js index f4c36fcf2202..d40aaba421d3 100644 --- a/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js +++ b/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js @@ -255,9 +255,14 @@ export default { } } } else if (name === 'useTransition') { - if (id.type === 'ArrayPattern' && isArray(resolved.identifiers)) { - // Is first tuple value the same reference we're checking? - if (id.elements[0] === resolved.identifiers[0]) { + // Only consider second value in initializing tuple stable. + if ( + id.type === 'ArrayPattern' && + id.elements.length === 2 && + Array.isArray(resolved.identifiers) + ) { + // Is second tuple value the same reference we're checking? + if (id.elements[1] === resolved.identifiers[0]) { // Setter is stable. return true; } diff --git a/packages/react-debug-tools/src/ReactDebugHooks.js b/packages/react-debug-tools/src/ReactDebugHooks.js index d78f62937484..212708255747 100644 --- a/packages/react-debug-tools/src/ReactDebugHooks.js +++ b/packages/react-debug-tools/src/ReactDebugHooks.js @@ -265,7 +265,7 @@ function useMutableSource( return value; } -function useTransition(): [(() => void) => void, boolean] { +function useTransition(): [boolean, (() => void) => void] { // useTransition() composes multiple hooks internally. // Advance the current hook index the same number of times // so that subsequent hooks have the right memoized state. @@ -276,7 +276,7 @@ function useTransition(): [(() => void) => void, boolean] { stackError: new Error(), value: undefined, }); - return [callback => {}, false]; + return [false, callback => {}]; } function useDeferredValue(value: T): T { diff --git a/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementErrorsAndWarningsTree.js b/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementErrorsAndWarningsTree.js index 3b7aaca3216d..83d3721a53dc 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementErrorsAndWarningsTree.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementErrorsAndWarningsTree.js @@ -41,8 +41,8 @@ export default function InspectedElementErrorsAndWarningsTree({ const refresh = useCacheRefresh(); const [ - startClearErrorsTransition, isErrorsTransitionPending, + startClearErrorsTransition, ] = useTransition(); const clearErrorsForInspectedElement = () => { const {id} = inspectedElement; @@ -60,8 +60,8 @@ export default function InspectedElementErrorsAndWarningsTree({ }; const [ - startClearWarningsTransition, isWarningsTransitionPending, + startClearWarningsTransition, ] = useTransition(); const clearWarningsForInspectedElement = () => { const {id} = inspectedElement; diff --git a/packages/react-devtools-shared/src/devtools/views/Components/KeyValue.js b/packages/react-devtools-shared/src/devtools/views/Components/KeyValue.js index aa5b1bc56eec..b39a6d154562 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/KeyValue.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/KeyValue.js @@ -90,7 +90,7 @@ export default function KeyValue({ isReadOnly = value[meta.readonly]; } - const [startInspectPathsTransition, isInspectPathsPending] = useTransition(); + const [isInspectPathsPending, startInspectPathsTransition] = useTransition(); const toggleIsOpen = () => { if (isOpen) { setIsOpen(false); diff --git a/packages/react-dom/src/server/ReactPartialRendererHooks.js b/packages/react-dom/src/server/ReactPartialRendererHooks.js index aeda6e72136f..433ab9ae078b 100644 --- a/packages/react-dom/src/server/ReactPartialRendererHooks.js +++ b/packages/react-dom/src/server/ReactPartialRendererHooks.js @@ -467,12 +467,12 @@ function useDeferredValue(value: T): T { return value; } -function useTransition(): [(callback: () => void) => void, boolean] { +function useTransition(): [boolean, (callback: () => void) => void] { resolveCurrentlyRenderingComponent(); const startTransition = callback => { callback(); }; - return [startTransition, false]; + return [false, startTransition]; } function useOpaqueIdentifier(): OpaqueIDType { diff --git a/packages/react-reconciler/src/ReactFiberHooks.new.js b/packages/react-reconciler/src/ReactFiberHooks.new.js index 5192c6d2740c..a507171aecd3 100644 --- a/packages/react-reconciler/src/ReactFiberHooks.new.js +++ b/packages/react-reconciler/src/ReactFiberHooks.new.js @@ -1723,27 +1723,27 @@ function startTransition(setPending, callback) { } } -function mountTransition(): [(() => void) => void, boolean] { +function mountTransition(): [boolean, (() => void) => void] { const [isPending, setPending] = mountState(false); // The `start` method never changes. const start = startTransition.bind(null, setPending); const hook = mountWorkInProgressHook(); hook.memoizedState = start; - return [start, isPending]; + return [isPending, start]; } -function updateTransition(): [(() => void) => void, boolean] { +function updateTransition(): [boolean, (() => void) => void] { const [isPending] = updateState(false); const hook = updateWorkInProgressHook(); const start = hook.memoizedState; - return [start, isPending]; + return [isPending, start]; } -function rerenderTransition(): [(() => void) => void, boolean] { +function rerenderTransition(): [boolean, (() => void) => void] { const [isPending] = rerenderState(false); const hook = updateWorkInProgressHook(); const start = hook.memoizedState; - return [start, isPending]; + return [isPending, start]; } let isUpdatingOpaqueValueInRenderPhase = false; @@ -2283,7 +2283,7 @@ if (__DEV__) { mountHookTypesDev(); return mountDeferredValue(value); }, - useTransition(): [(() => void) => void, boolean] { + useTransition(): [boolean, (() => void) => void] { currentHookNameInDev = 'useTransition'; mountHookTypesDev(); return mountTransition(); @@ -2407,7 +2407,7 @@ if (__DEV__) { updateHookTypesDev(); return mountDeferredValue(value); }, - useTransition(): [(() => void) => void, boolean] { + useTransition(): [boolean, (() => void) => void] { currentHookNameInDev = 'useTransition'; updateHookTypesDev(); return mountTransition(); @@ -2531,7 +2531,7 @@ if (__DEV__) { updateHookTypesDev(); return updateDeferredValue(value); }, - useTransition(): [(() => void) => void, boolean] { + useTransition(): [boolean, (() => void) => void] { currentHookNameInDev = 'useTransition'; updateHookTypesDev(); return updateTransition(); @@ -2656,7 +2656,7 @@ if (__DEV__) { updateHookTypesDev(); return rerenderDeferredValue(value); }, - useTransition(): [(() => void) => void, boolean] { + useTransition(): [boolean, (() => void) => void] { currentHookNameInDev = 'useTransition'; updateHookTypesDev(); return rerenderTransition(); @@ -2792,7 +2792,7 @@ if (__DEV__) { mountHookTypesDev(); return mountDeferredValue(value); }, - useTransition(): [(() => void) => void, boolean] { + useTransition(): [boolean, (() => void) => void] { currentHookNameInDev = 'useTransition'; warnInvalidHookAccess(); mountHookTypesDev(); @@ -2931,7 +2931,7 @@ if (__DEV__) { updateHookTypesDev(); return updateDeferredValue(value); }, - useTransition(): [(() => void) => void, boolean] { + useTransition(): [boolean, (() => void) => void] { currentHookNameInDev = 'useTransition'; warnInvalidHookAccess(); updateHookTypesDev(); @@ -3071,7 +3071,7 @@ if (__DEV__) { updateHookTypesDev(); return rerenderDeferredValue(value); }, - useTransition(): [(() => void) => void, boolean] { + useTransition(): [boolean, (() => void) => void] { currentHookNameInDev = 'useTransition'; warnInvalidHookAccess(); updateHookTypesDev(); diff --git a/packages/react-reconciler/src/ReactFiberHooks.old.js b/packages/react-reconciler/src/ReactFiberHooks.old.js index a319cdf75b67..ad555804319c 100644 --- a/packages/react-reconciler/src/ReactFiberHooks.old.js +++ b/packages/react-reconciler/src/ReactFiberHooks.old.js @@ -1723,27 +1723,27 @@ function startTransition(setPending, callback) { } } -function mountTransition(): [(() => void) => void, boolean] { +function mountTransition(): [boolean, (() => void) => void] { const [isPending, setPending] = mountState(false); // The `start` method never changes. const start = startTransition.bind(null, setPending); const hook = mountWorkInProgressHook(); hook.memoizedState = start; - return [start, isPending]; + return [isPending, start]; } -function updateTransition(): [(() => void) => void, boolean] { +function updateTransition(): [boolean, (() => void) => void] { const [isPending] = updateState(false); const hook = updateWorkInProgressHook(); const start = hook.memoizedState; - return [start, isPending]; + return [isPending, start]; } -function rerenderTransition(): [(() => void) => void, boolean] { +function rerenderTransition(): [boolean, (() => void) => void] { const [isPending] = rerenderState(false); const hook = updateWorkInProgressHook(); const start = hook.memoizedState; - return [start, isPending]; + return [isPending, start]; } let isUpdatingOpaqueValueInRenderPhase = false; @@ -2283,7 +2283,7 @@ if (__DEV__) { mountHookTypesDev(); return mountDeferredValue(value); }, - useTransition(): [(() => void) => void, boolean] { + useTransition(): [boolean, (() => void) => void] { currentHookNameInDev = 'useTransition'; mountHookTypesDev(); return mountTransition(); @@ -2407,7 +2407,7 @@ if (__DEV__) { updateHookTypesDev(); return mountDeferredValue(value); }, - useTransition(): [(() => void) => void, boolean] { + useTransition(): [boolean, (() => void) => void] { currentHookNameInDev = 'useTransition'; updateHookTypesDev(); return mountTransition(); @@ -2531,7 +2531,7 @@ if (__DEV__) { updateHookTypesDev(); return updateDeferredValue(value); }, - useTransition(): [(() => void) => void, boolean] { + useTransition(): [boolean, (() => void) => void] { currentHookNameInDev = 'useTransition'; updateHookTypesDev(); return updateTransition(); @@ -2656,7 +2656,7 @@ if (__DEV__) { updateHookTypesDev(); return rerenderDeferredValue(value); }, - useTransition(): [(() => void) => void, boolean] { + useTransition(): [boolean, (() => void) => void] { currentHookNameInDev = 'useTransition'; updateHookTypesDev(); return rerenderTransition(); @@ -2792,7 +2792,7 @@ if (__DEV__) { mountHookTypesDev(); return mountDeferredValue(value); }, - useTransition(): [(() => void) => void, boolean] { + useTransition(): [boolean, (() => void) => void] { currentHookNameInDev = 'useTransition'; warnInvalidHookAccess(); mountHookTypesDev(); @@ -2931,7 +2931,7 @@ if (__DEV__) { updateHookTypesDev(); return updateDeferredValue(value); }, - useTransition(): [(() => void) => void, boolean] { + useTransition(): [boolean, (() => void) => void] { currentHookNameInDev = 'useTransition'; warnInvalidHookAccess(); updateHookTypesDev(); @@ -3071,7 +3071,7 @@ if (__DEV__) { updateHookTypesDev(); return rerenderDeferredValue(value); }, - useTransition(): [(() => void) => void, boolean] { + useTransition(): [boolean, (() => void) => void] { currentHookNameInDev = 'useTransition'; warnInvalidHookAccess(); updateHookTypesDev(); diff --git a/packages/react-reconciler/src/ReactInternalTypes.js b/packages/react-reconciler/src/ReactInternalTypes.js index 0c34eeda8ed6..08f5cbc2d0e9 100644 --- a/packages/react-reconciler/src/ReactInternalTypes.js +++ b/packages/react-reconciler/src/ReactInternalTypes.js @@ -311,7 +311,7 @@ export type Dispatcher = {| ): void, useDebugValue(value: T, formatterFn: ?(value: T) => mixed): void, useDeferredValue(value: T): T, - useTransition(): [(() => void) => void, boolean], + useTransition(): [boolean, (() => void) => void], useMutableSource( source: MutableSource, getSnapshot: MutableSourceGetSnapshotFn, diff --git a/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js b/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js index bc37abbd322f..ce9236e114b9 100644 --- a/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js @@ -1511,7 +1511,7 @@ describe('ReactHooks', () => { ]; if (__EXPERIMENTAL__) { - const useTransitionHelper = () => React.useTransition({timeoutMs: 1000}); + const useTransitionHelper = () => React.useTransition(); const useDeferredValueHelper = () => React.useDeferredValue(0, {timeoutMs: 1000}); diff --git a/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.js b/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.js index d01cd2a06537..95e6a55c7835 100644 --- a/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.js +++ b/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.js @@ -876,14 +876,11 @@ describe('ReactHooksWithNoopRenderer', () => { // TODO: This should probably warn // @gate experimental it('calling startTransition inside render phase', async () => { - let startTransition; function App() { const [counter, setCounter] = useState(0); - const [_startTransition] = useTransition(); - startTransition = _startTransition; if (counter === 0) { - startTransition(() => { + React.unstable_startTransition(() => { setCounter(c => c + 1); }); } @@ -3227,9 +3224,7 @@ describe('ReactHooksWithNoopRenderer', () => { let transition; function App() { const [show, setShow] = useState(false); - const [startTransition, isPending] = useTransition({ - timeoutMs: 1000, - }); + const [isPending, startTransition] = useTransition(); transition = () => { startTransition(() => { setShow(true); diff --git a/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.js b/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.js index bb4e0f6892a6..7861b2904f28 100644 --- a/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.js +++ b/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.js @@ -3745,7 +3745,8 @@ describe('ReactSuspenseWithNoopRenderer', () => { let startTransition; function B() { const [textB, _setTextB] = useState('B'); - const [_startTransition] = useTransition({timeoutMs: 10000}); + // eslint-disable-next-line no-unused-vars + const [_, _startTransition] = useTransition(); startTransition = _startTransition; setTextB = _setTextB; return ( @@ -3843,12 +3844,8 @@ describe('ReactSuspenseWithNoopRenderer', () => { let setTextWithLongTransition; function App() { - const [startShortTransition, isPending1] = React.unstable_useTransition({ - timeoutMs: 5000, - }); - const [startLongTransition, isPending2] = React.unstable_useTransition({ - timeoutMs: 30000, - }); + const [isPending1, startShortTransition] = React.unstable_useTransition(); + const [isPending2, startLongTransition] = React.unstable_useTransition(); const isPending = isPending1 || isPending2; const [text, setText] = React.useState(''); const [mirror, setMirror] = React.useState(''); diff --git a/packages/react-reconciler/src/__tests__/ReactTransition-test.js b/packages/react-reconciler/src/__tests__/ReactTransition-test.js index 09ba5dded730..71c40cefebe8 100644 --- a/packages/react-reconciler/src/__tests__/ReactTransition-test.js +++ b/packages/react-reconciler/src/__tests__/ReactTransition-test.js @@ -164,7 +164,7 @@ describe('ReactTransition', () => { let start; function App() { const [show, setShow] = useState(false); - const [_start, isPending] = useTransition(); + const [isPending, _start] = useTransition(); start = () => _start(() => setShow(true)); return ( }> @@ -208,7 +208,7 @@ describe('ReactTransition', () => { async () => { let update; function App() { - const [startContentChange, isContentPending] = useTransition(); + const [isContentPending, startContentChange] = useTransition(); const [label, setLabel] = useState('A'); const [contents, setContents] = useState('A'); update = value => { diff --git a/packages/react-server/src/ReactFizzHooks.js b/packages/react-server/src/ReactFizzHooks.js index 9fd9e0f42098..23a35c1803f7 100644 --- a/packages/react-server/src/ReactFizzHooks.js +++ b/packages/react-server/src/ReactFizzHooks.js @@ -470,9 +470,9 @@ function unsupportedStartTransition() { invariant(false, 'startTransition cannot be called during server rendering.'); } -function useTransition(): [(callback: () => void) => void, boolean] { +function useTransition(): [boolean, (callback: () => void) => void] { resolveCurrentlyRenderingComponent(); - return [unsupportedStartTransition, false]; + return [false, unsupportedStartTransition]; } function useOpaqueIdentifier(): OpaqueIDType { diff --git a/packages/react/src/ReactHooks.js b/packages/react/src/ReactHooks.js index 18920be2c8df..82bd886d8245 100644 --- a/packages/react/src/ReactHooks.js +++ b/packages/react/src/ReactHooks.js @@ -145,7 +145,7 @@ export function useDebugValue( export const emptyObject = {}; -export function useTransition(): [(() => void) => void, boolean] { +export function useTransition(): [boolean, (() => void) => void] { const dispatcher = resolveDispatcher(); return dispatcher.useTransition(); }