Skip to content

bug(react-native): useAskableVisibility and useAskableScrollView leak context when ctx prop changes #250

@vamgan

Description

@vamgan

Summary

Both useAskableVisibility and useAskableScrollView create an internal context via useState when no ctx is provided. The cleanup effect is supposed to destroy that internal context on unmount — but the cleanup condition checks the options parameter ctx, not the state variable, causing it to always run (or never run) incorrectly if the parent later provides a different context.

Root cause

packages/react-native/src/useAskableVisibility.ts:

const [visibilityCtx] = useState<AskableContext>(
  () => ctx ?? createAskableContext(options)
);

useEffect(() => {
  return () => {
    if (!ctx) {           // ← checks the CURRENT options.ctx prop
      visibilityCtx.destroy(); // ← but visibilityCtx was created based on ctx at mount time
    }
  };
}, [ctx, visibilityCtx]);

If a parent passes ctx={undefined} at mount (so an internal context is created) and later passes ctx={someCtx}, the cleanup will NOT destroy the original internal context because at cleanup time ctx is now truthy.

The identical pattern exists in useAskableScrollView.ts.

Expected behavior

Whether to destroy the internal context should be decided at creation time (was a context created internally?) and stored alongside it, not re-evaluated at cleanup time from the current prop value.

Fix

const [{ visibilityCtx, owned }] = useState(() => {
  const provided = ctx;
  return provided
    ? { visibilityCtx: provided, owned: false }
    : { visibilityCtx: createAskableContext(options), owned: true };
});

useEffect(() => {
  return () => {
    if (owned) visibilityCtx.destroy();
  };
}, [visibilityCtx, owned]);

Same fix applies to useAskableScrollView.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions