jeecgboot/JeecgBoot · error

useDrawerInner() can only be used inside setup() or function

Error message

useDrawerInner() can only be used inside setup() or functional components!

What it means

useDrawerInner is the inner-side hook used by the component rendered inside a Drawer (it receives data transferred from the opener and accesses the drawer instance). It captures getCurrentInstance() into a variable and also re-checks it in the guard. Like useDrawer, it requires a setup context because it registers lifecycle cleanup. The double getCurrentInstance() call is redundant but harmless. It throws the same class of message when no instance is present.

Source

Thrown at jeecgboot-vue3/src/components/Drawer/src/useDrawer.ts:97

        dataTransferRef[unref(uid)] = toRaw(data);
      }
    },
    closeDrawer: () => {
      // 代码逻辑说明: 【QQYUN-6366】升级到antd4.x
      getInstance()?.setDrawerProps({ open: false });
    },
  };

  return [register, methods];
}

export const useDrawerInner = (callbackFn?: Fn): UseDrawerInnerReturnType => {
  const drawerInstanceRef = ref<Nullable<DrawerInstance>>(null);
  const currentInstance = getCurrentInstance();
  const uidRef = ref<string>('');

  if (!getCurrentInstance()) {
    throw new Error('useDrawerInner() can only be used inside setup() or functional components!');
  }

  const getInstance = () => {
    const instance = unref(drawerInstanceRef);
    if (!instance) {
      error('useDrawerInner instance is undefined!');
      return;
    }
    return instance;
  };

  const register = (modalInstance: DrawerInstance, uuid: string) => {
    isProdMode() &&
      tryOnUnmounted(() => {
        drawerInstanceRef.value = null;
      });

    uidRef.value = uuid;

View on GitHub (pinned to 96fb33f5ec)

Solutions

  1. Call useDrawerInner() at the top of the inner component's <script setup>.
  2. Ensure the inner drawer content is defined as a proper Vue component (defineComponent or <script setup>).
  3. Do not call useDrawerInner from the parent/opener component — it belongs only in the inner view.
  4. If using a callback function parameter, ensure it does not itself call the hook; pass it as an argument instead.

Example fix

// before — inner logic placed in a helper file
// drawerHelper.ts
export function setupDrawer() {
  const [register] = useDrawerInner(cb); // throws
}

// after — move into the actual inner .vue component
// InnerDrawer.vue <script setup>
const [register] = useDrawerInner((data) => { /* ... */ });
Defensive patterns

Strategy: validation

Validate before calling

import { getCurrentInstance } from 'vue';
function safeUseDrawerInner(cb?: Fn) {
  if (!getCurrentInstance()) {
    console.error('useDrawerInner must be called inside the inner drawer component setup');
    return null;
  }
  return useDrawerInner(cb);
}

Type guard

import { getCurrentInstance } from 'vue';
const canUseLifecycle = () => !!getCurrentInstance();

Try / catch

try {
  const [register] = useDrawerInner(cb);
} catch (e) {
  // move the call into the inner .vue component's setup
}

Prevention

When it happens

Trigger: Calling useDrawerInner() in a non-component module, a Pinia store, a composable invoked outside setup, or any detached async context. Because the inner component is usually a child route/view, a common trigger is the child view failing to be a real Vue component (e.g. a plain function returning JSX without defineComponent).

Common situations: Refactoring the inner drawer view into a separate file but calling the hook in a utility; using useDrawerInner inside a render function without a proper component definition; calling it during SSR where instance availability differs.

Related errors


AI-assisted analysis of jeecgboot/JeecgBoot@96fb33f5ec (2026-08-14). Data as JSON: /api/errors/c16c32ffbeaff3b1. Report an issue: GitHub.