jeecgboot/JeecgBoot · error
useTableContext must be used after createTableContext
Error message
useTableContext must be used after createTableContext
What it means
useTableContext uses Vue's provide/inject with a dynamic Symbol key. The parent table calls createTableContext (which provides a Symbol under '__BASIC_TABLE_CONTEXT_KEY__'), and child cells/features call useTableContext to inject the table instance. If a child invokes useTableContext but no ancestor has called createTableContext, the inject returns undefined and the guard throws. This enforces that context-only features are never used detached from a table.
Source
Thrown at jeecgboot-vue3/src/components/Table/src/hooks/useTableContext.ts:30
};
type RetInstance = Omit<Instance, 'getBindValues'> & {
getBindValues: ComputedRef<BasicTableProps>;
};
export function createTableContext(instance: Instance) {
// 每次创建 context 时都生成新的唯一 Symbol
const key = Symbol(`basic-table-${++tableIdCounter}`);
provide(key, instance);
// 同时提供一个内部标记,让子组件能获取到这个 key
provide('__BASIC_TABLE_CONTEXT_KEY__', key);
}
export function useTableContext(): RetInstance {
// 从最近的父组件获取 context key
const key = inject<symbol>('__BASIC_TABLE_CONTEXT_KEY__');
if (!key) {
throw new Error('useTableContext must be used after createTableContext');
}
return inject(key) as RetInstance;
}
View on GitHub (pinned to 96fb33f5ec)
Solutions
- Ensure the component calling useTableContext is always a descendant of a BasicTable/JVxeTable that calls createTableContext.
- In tests/stories, wrap the component in a minimal table or mock the provide('__BASIC_TABLE_CONTEXT_KEY__') call.
- Add a v-if guard so the child only renders when inside a table (pass an `inTable` prop).
- If you need table-like features standalone, refactor to pass the instance via props instead of inject.
Example fix
// before — cell used outside a table <MyCustomCell /> <!-- calls useTableContext, throws --> // after — wrap in a table provider, or guard <BasicTable> <MyCustomCell /> </BasicTable>
Defensive patterns
Strategy: type-guard
Validate before calling
// Check inject availability before using context
import { inject } from 'vue';
function useTableContextOrNull() {
const key = inject<symbol>('__BASIC_TABLE_CONTEXT_KEY__');
if (!key) return null;
return inject(key);
} Type guard
import { inject } from 'vue';
function isInsideTable(): boolean {
return !!inject<symbol>('__BASIC_TABLE_CONTEXT_KEY__');
} Try / catch
try {
const ctx = useTableContext();
} catch (e) {
// not inside a table; render a fallback or skip
} Prevention
- Only render context-dependent children as descendants of the table provider.
- In stories/tests, wrap cells in a table or mock the provide call.
- Add an inTable prop to opt into context usage.
When it happens
Trigger: A JVxeTable cell component or a feature hook (e.g. a toolbar or pagination sub-component) rendered outside of a <JVxeTable> or <BasicTable> wrapper. Also triggered when a cell is rendered in a preview/storybook environment without the table provider, or when the table's createTableContext is conditionally skipped.
Common situations: Reusing a table cell component in a standalone form or grid; rendering table sub-components in isolation for testing; refactoring that moves a cell outside the table slot; conditional rendering that skips the table wrapper but still renders children.
Related errors
- useDescription() can only be used inside setup() or function
- useDrawer() can only be used inside setup() or functional co
- useDrawerInner() can only be used inside setup() or function
- useModal() can only be used inside setup() or functional com
- 【addComponent】不能使用"${type}"作为组件的name,因为这是关键字。
AI-assisted analysis of jeecgboot/JeecgBoot@96fb33f5ec (2026-08-14).
Data as JSON: /api/errors/d6b1489f19ad2767.
Report an issue: GitHub.