{"record":{"id":"d794612183ee05a4","repo":"oxc-project/oxc","slug":"data-property-in-component-must-be-a-function","errorCode":null,"errorMessage":"`data` property in component must be a function.","messagePattern":"`data` property in component must be a function\\.","errorType":"validation","errorClass":"OxcDiagnostic","httpStatus":null,"severity":"error","filePath":"crates/oxc_linter/src/rules/vue/no_shared_component_data.rs","lineNumber":12,"sourceCode":"use oxc_ast::{AstKind, ast::Expression};\nuse oxc_diagnostics::OxcDiagnostic;\nuse oxc_macros::declare_oxc_lint;\nuse oxc_span::Span;\n\nuse crate::{\n    AstNode, context::LintContext, rule::Rule,\n    utils::is_vue_component_options_object_excluding_instance,\n};\n\nfn no_shared_component_data_diagnostic(span: Span) -> OxcDiagnostic {\n    OxcDiagnostic::warn(\"`data` property in component must be a function.\").with_label(span)\n}\n\n#[derive(Debug, Default, Clone)]\npub struct NoSharedComponentData;\n\ndeclare_oxc_lint!(\n    /// ### What it does\n    ///\n    /// Enforce that the `data` property of a Vue component definition is a\n    /// function.\n    ///\n    /// ### Why is this bad?\n    ///\n    /// When `data` is declared as an object literal, the same object is shared\n    /// across every instance of the component, which causes cross-instance\n    /// state pollution. Returning a fresh object from a function avoids that.\n    ///\n    /// This rule targets component definitions reached through","sourceCodeStart":1,"sourceCodeEnd":30,"githubUrl":"https://github.com/oxc-project/oxc/blob/e1e7af627c8843ab64044ed466b128fcc21a035b/crates/oxc_linter/src/rules/vue/no_shared_component_data.rs#L1-L30","documentation":"The vue/no-shared-component-data rule enforces that a component's `data` option is a function. When `data` is a plain object, every instance of the component shares the same object, so state mutations in one instance leak into all others. The rule checks objects recognized as component definitions while excluding root instances (is_vue_component_options_object_excluding_instance), because `new Vue({ data: {...} })` legitimately allows an object at the app root.","triggerScenarios":"An Options-API component with `data: { ... }` (object literal) instead of `data() { return {...} }`, or `defineComponent({ data: {...} })` — anywhere the object is recognized as a component definition rather than a root instance.","commonSituations":"Quick prototypes written with object data then reused in lists; copy-pasting the root-instance pattern into child components; code migrated from Vue 1 where object data was allowed; bugs that look like 'all rows in my table update together'.","solutions":["Convert `data` to a function returning the object: `data() { return { count: 0 }; }`.","Audit sibling components for the same object-data pattern.","Keep object data only at the true root instance if you rely on it, and note the rule intentionally skips that case.","Re-run oxlint to confirm."],"exampleFix":"// before\nexport default {\n  data: { count: 0 } // shared across all instances\n}\n\n// after\nexport default {\n  data() {\n    return { count: 0 };\n  }\n}","handlingStrategy":"validation","validationCode":"// sanity check component options before registration\nfunction registerComponent(opts) {\n  if (opts.data && typeof opts.data !== 'function') {\n    throw new TypeError('component `data` must be a function');\n  }\n  // ...register\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always author component `data` as a function returning a fresh object.","Remember only the root instance (`new Vue({ data })`) may use an object.","When a list of components mysteriously share state, check for object-data first."],"tags":["vue","data","lint","options-api","shared-state"],"backgroundTag":"shared-mutable-state","analyzedSha":"e1e7af627c8843ab64044ed466b128fcc21a035b","analyzedAt":"2026-08-20T07:01:07.079Z","contentChangedAt":"2026-08-20T07:01:07.079Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}