Repository: facebook/react
File: packages/react-reconciler/src/ReactFiberHooks.js (JavaScript)

Code before:
  }
  if (queue.pending !== null) {
    // As long as there are any active gestures we need to leave the lane on
    // in case we need to render it later. Since a gesture render doesn't commit
    // the only time it really fully gets cleared is if something else rerenders
    // this component after all the active gestures has cleared.
    currentlyRenderingFiber.lanes = mergeLanes(
      currentlyRenderingFiber.lanes,
      GestureLane,
    );
  }
  return [value, startGestureOnHook];
}

export const ContextOnlyDispatcher: Dispatcher = {
  readContext,

  use,
  useCallback: throwInvalidHookError,
  useContext: throwInvalidHookError,
  useEffect: throwInvalidHookError,
  useImperativeHandle: throwInvalidHookError,
  useLayoutEffect: throwInvalidHookError,
  useInsertionEffect: throwInvalidHookError,
  useMemo: throwInvalidHookError,
  useReducer: throwInvalidHookError,
  useRef: throwInvalidHookError,
  useState: throwInvalidHookError,
  useDebugValue: throwInvalidHookError,
  useDeferredValue: throwInvalidHookError,
  useTransition: throwInvalidHookError,
  useSyncExternalStore: throwInvalidHookError,
  useId: throwInvalidHookError,
  useHostTransitionStatus: throwInvalidHookError,
  useFormState: throwInvalidHookError,
  useActionState: throwInvalidHookError,
  useOptimistic: throwInvalidHookError,
  useMemoCache: throwInvalidHookError,
  useCacheRefresh: throwInvalidHookError,
};
if (enableUseEffectEventHook) {
  (ContextOnlyDispatcher: Dispatcher).useEffectEvent = throwInvalidHookError;
}
if (enableSwipeTransition) {
  (ContextOnlyDispatcher: Dispatcher).useSwipeTransition =
    throwInvalidHookError;
}

const HooksDispatcherOnMount: Dispatcher = {
  readContext,


Review comment (bug):
Double checking my understanding: Seems that if this is wrong, the result is an immediate cancel, rerender with the correct direction, but that rerender would have no effect if its a single direction gesture. 

For the stack navigation use case, if there's no page to go back to, `previous` and `current` would be the same, making the initial direction `next`. If you are in the middle of a stack and can go in both directions, then this is just a guess and we rely on the immediate cancel when moving to `next`.

Code after:
          if (rootRenderGesture === update.gesture) {
            // We had a match, meaning we're currently rendering a direction of this
            // hook for this gesture.
            value = rootRenderGesture.direction ? next : previous;
            break;
          }
          update = update.next;
        }
      }
      // This lane cannot be cleared as long as we have active gestures.
      markWorkInProgressReceivedUpdate();
    }
    // As long as there are any active gestures we need to leave the lane on
    // in case we need to render it later. Since a gesture render doesn't commit
    // the only time it really fully gets cleared is if something else rerenders
    // this component after all the active gestures has cleared.
    currentlyRenderingFiber.lanes = mergeLanes(
      currentlyRenderingFiber.lanes,
      GestureLane,
    );
  }
  // By default, we don't know which direction we should start until a movement
  // has happened. However, if one direction has the same value as current we
  // know that it's probably not that direction since it won't do anything anyway.
  // TODO: Add an explicit option to provide this.
  queue.initialDirection = previous === current;
  return [value, startGestureOnHook];
}

export const ContextOnlyDispatcher: Dispatcher = {
  readContext,

  use,
  useCallback: throwInvalidHookError,
  useContext: throwInvalidHookError,
  useEffect: throwInvalidHookError,
  useImperativeHandle: throwInvalidHookError,
  useLayoutEffect: throwInvalidHookError,
  useInsertionEffect: throwInvalidHookError,
  useMemo: throwInvalidHookError,
  useReducer: throwInvalidHookError,
  useRef: throwInvalidHookError,
  useState: throwInvalidHookError,
  useDebugValue: throwInvalidHookError,
  useDeferredValue: throwInvalidHookError,
  useTransition: throwInvalidHookError,
  useSyncExternalStore: throwInvalidHookError,
  useId: throwInvalidHookError,
  useHostTransitionStatus: throwInvalidHookError,
  useFormState: throwInvalidHookError,
  useActionState: throwInvalidHookError,