Skip to content

bug(react): useAskableRegionCapture stale closure — onCapture/onCancel from previous start() call can fire #269

Closed

Description

@vamgan

Summary

In packages/react/src/useAskableRegionCapture.ts, the start() callback captures currentOptions in a closure and passes it to createAskableRegionCapture. If start() is called a second time before the first capture completes, the new call destroys the first handle — but any in-flight async callbacks from the destroyed handle still hold a reference to their currentOptions closure. Those callbacks will fire with the wrong options.

Root cause

const start = useCallback((overrides?) => {
  handleRef.current?.destroy();

  const currentOptions = { ...optionsRef.current, ...overrides };

  const handle = createAskableRegionCapture(ctx, {
    ...currentOptions,
    onCapture(packet, selection) {
      // currentOptions is captured here
      currentOptions.onCapture?.(packet, selection);   // ← stale if start() was called again
    },
    onCancel() {
      currentOptions.onCancel?.();  // ← stale
    },
  });

  handleRef.current = handle;
  handle.start();
}, [ctx]);

Fix

Use a ref for callbacks so the latest version is always called:

const onCaptureRef = useRef(options.onCapture);
const onCancelRef  = useRef(options.onCancel);

useEffect(() => {
  onCaptureRef.current = options.onCapture;
  onCancelRef.current  = options.onCancel;
});

// In the capture setup:
onCapture: (packet, selection) => onCaptureRef.current?.(packet, selection),
onCancel:  () => onCancelRef.current?.(),

The same issue exists in useAskableTextSelectionCapture.ts and the Vue equivalent.

Impact

A rapid double-click on "start capture" or programmatic back-to-back starts can invoke the wrong callback, e.g. the old onCapture handler fires when the new capture completes.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: reactReact adapter workbugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions