{"record":{"id":"c6024e69b91f6115","repo":"jeecgboot/JeecgBoot","slug":"usedrawer-can-only-be-used-inside-setup-or-fun","errorCode":null,"errorMessage":"useDrawer() can only be used inside setup() or functional components!","messagePattern":"useDrawer\\(\\) can only be used inside setup\\(\\) or functional components!","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"jeecgboot-vue3/src/components/Drawer/src/useDrawer.ts","lineNumber":18,"sourceCode":"import type { UseDrawerReturnType, DrawerInstance, ReturnMethods, DrawerProps, UseDrawerInnerReturnType } from './typing';\nimport { ref, getCurrentInstance, unref, reactive, watchEffect, nextTick, toRaw, computed } from 'vue';\nimport { isProdMode } from '/@/utils/env';\nimport { isFunction } from '/@/utils/is';\nimport { tryOnUnmounted } from '@vueuse/core';\nimport { isEqual } from 'lodash-es';\nimport { error } from '/@/utils/log';\n\nconst dataTransferRef = reactive<any>({});\n\nconst visibleData = reactive<{ [key: number]: boolean }>({});\n\n/**\n * @description: Applicable to separate drawer and call outside\n */\nexport function useDrawer(): UseDrawerReturnType {\n  if (!getCurrentInstance()) {\n    throw new Error('useDrawer() can only be used inside setup() or functional components!');\n  }\n  const drawer = ref<DrawerInstance | null>(null);\n  const loaded = ref<Nullable<boolean>>(false);\n  const uid = ref<string>('');\n\n  function register(drawerInstance: DrawerInstance, uuid: string) {\n    isProdMode() &&\n      tryOnUnmounted(() => {\n        drawer.value = null;\n        loaded.value = null;\n        dataTransferRef[unref(uid)] = null;\n      });\n\n    if (unref(loaded) && isProdMode() && drawerInstance === unref(drawer)) {\n      return;\n    }\n    uid.value = uuid;\n    drawer.value = drawerInstance;","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/jeecgboot/JeecgBoot/blob/96fb33f5ec68516da0b0147da06b2eb0419e063a/jeecgboot-vue3/src/components/Drawer/src/useDrawer.ts#L1-L36","documentation":"useDrawer is the controller-side hook for the Drawer component pair (useDrawer/useDrawerInner). It creates a ref to hold the drawer instance and registers tryOnUnmounted cleanup for the data-transfer map and visible-state tracking. Because the cleanup and the uid ref rely on an active component instance, the hook guards with getCurrentInstance() and throws if invoked outside a setup context. This mirrors the pattern used by useModal and useDescription.","triggerScenarios":"Calling useDrawer() inside a non-setup function, a Pinia store, a utility module, a router guard, or any async continuation that has lost the component instance. Also triggered when the hook is imported and invoked in a plain .ts file rather than a .vue component.","commonSituations":"Moving drawer-control logic into a shared composable or store; calling openDrawer from a global event bus handler; refactoring that splits the register call from setup; testing the hook in isolation without a Vue instance.","solutions":["Call useDrawer() synchronously at the top of <script setup> or setup().","If you need to control the drawer from outside setup, keep the hook call in setup and expose/return the methods to wherever they are needed.","Ensure the component using useDrawer is actually rendered within a Vue component tree (not a standalone function).","For shared cross-component drawer control, use a Pinia store that holds the methods reference rather than calling the hook repeatedly."],"exampleFix":"// before — hook called in a store action\nactions: {\n  openDrawer() {\n    const [register, methods] = useDrawer(); // throws\n  }\n}\n\n// after — call in component setup, delegate to store\n// MyPage.vue\nconst [register, methods] = useDrawer();\ndrawerStore.setMethods(methods);","handlingStrategy":"validation","validationCode":"import { getCurrentInstance } from 'vue';\nfunction safeUseDrawer() {\n  if (!getCurrentInstance()) {\n    throw new Error('useDrawer must be called in setup(); move the call into <script setup>');\n  }\n  return useDrawer();\n}","typeGuard":"import { getCurrentInstance } from 'vue';\nconst isInsideComponent = () => getCurrentInstance() !== null;","tryCatchPattern":"try {\n  const [register, methods] = useDrawer();\n} catch (e) {\n  // recover by deferring drawer control to a store set in setup\n}","preventionTips":["Keep useDrawer() calls in <script setup> only.","For cross-component control, store the returned methods in Pinia rather than re-calling the hook.","Lint for hook calls outside .vue files."],"tags":["vue3","composition-api","drawer","setup","lifecycle"],"backgroundTag":null,"analyzedSha":"96fb33f5ec68516da0b0147da06b2eb0419e063a","analyzedAt":"2026-08-14T00:04:16.786Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}