{"record":{"id":"a340dc78ee58eaee","repo":"facebook/react","slug":"s-is-deprecated-in-plain-javascript-react-cl","errorCode":null,"errorMessage":"%s(...) is deprecated in plain JavaScript React classes. %s","messagePattern":"(.+?)\\(\\.\\.\\.\\) is deprecated in plain JavaScript React classes\\. (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/react/src/ReactBaseClasses.js","lineNumber":110,"sourceCode":" * modern base class. Instead, we define a getter that warns if it's accessed.\n */\nif (__DEV__) {\n  const deprecatedAPIs = {\n    isMounted: [\n      'isMounted',\n      'Instead, make sure to clean up subscriptions and pending requests in ' +\n        'componentWillUnmount to prevent memory leaks.',\n    ],\n    replaceState: [\n      'replaceState',\n      'Refactor your code to use setState instead (see ' +\n        'https://github.com/facebook/react/issues/3236).',\n    ],\n  };\n  const defineDeprecationWarning = function (methodName, info) {\n    Object.defineProperty(Component.prototype, methodName, {\n      get: function () {\n        console.warn(\n          '%s(...) is deprecated in plain JavaScript React classes. %s',\n          info[0],\n          info[1],\n        );\n        return undefined;\n      },\n    });\n  };\n  for (const fnName in deprecatedAPIs) {\n    if (deprecatedAPIs.hasOwnProperty(fnName)) {\n      defineDeprecationWarning(fnName, deprecatedAPIs[fnName]);\n    }\n  }\n}\n\nfunction ComponentDummy() {}\nComponentDummy.prototype = Component.prototype;\n","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/facebook/react/blob/eafeac097ba51e1eab809c07102126bd5f8e5425/packages/react/src/ReactBaseClasses.js#L92-L128","documentation":"In dev builds, React defines isMounted and replaceState as getter-only properties on Component.prototype (ReactBaseClasses.js:110) that console.warn and return undefined when accessed. These createClass-era APIs were never part of the ES6 base class; the getters exist purely to catch ported code. Because the getter returns undefined, code like this.isMounted() warns and then throws TypeError: not a function.","triggerScenarios":"Any access - even a truthiness check or feature test - of this.isMounted or this.replaceState inside a class component, including access from mixins or utilities holding the instance. Production builds define nothing, so this.isMounted is plain undefined.","commonSituations":"Legacy code guarding async setState after unmount; components migrated from React.createClass; old tutorials and enterprise code copied between projects for years.","solutions":["Track mounted state yourself: set this._isMounted = true in componentDidMount, false in componentWillUnmount","Better: cancel async work in componentWillUnmount (AbortController/subscription teardown) instead of checking mounted before setState","Replace replaceState(next) with setState handing every top-level key you want replaced","Add eslint-plugin-react's no-is-mounted rule to block regressions"],"exampleFix":"// before\nfetchUser(id).then(u => { if (this.isMounted()) this.setState({user: u}); });\n\n// after\ncomponentDidMount() {\n  this._cancelled = false;\n  fetchUser(id).then(u => { if (!this._cancelled) this.setState({user: u}); });\n}\ncomponentWillUnmount() { this._cancelled = true; }","handlingStrategy":"validation","validationCode":"// detect the dev-only getter WITHOUT accessing it (access triggers the warning)\nfunction hasDeprecatedClassAPIs() {\n  if (process.env.NODE_ENV !== 'production') {\n    const d = Object.getOwnPropertyDescriptor(\n      Object.getPrototypeOf(Object.getPrototypeOf(this)) ?? {},\n      'isMounted',\n    );\n    return Boolean(d && d.get);\n  }\n  return false;\n}","typeGuard":"function definesDeprecatedClassAPI(instance, name) {\n  let proto = Object.getPrototypeOf(instance);\n  while (proto && proto !== Object.prototype) {\n    const d = Object.getOwnPropertyDescriptor(proto, name);\n    if (d && d.get) return true;\n    proto = Object.getPrototypeOf(proto);\n  }\n  return false;\n}","tryCatchPattern":null,"preventionTips":["Enable eslint-plugin-react's no-is-mounted rule","Grep the codebase for isMounted and replaceState before React 18/19 upgrades","Use componentWillUnmount cleanup (flags, AbortController) instead of mounted checks","Remember even `if (this.isMounted)` triggers the warning - it fires on property access, not on call"],"tags":["deprecated-api","ismounted","replacestate","class-components","mixin-era","dev-only"],"backgroundTag":"deprecated-class-api","analyzedSha":"eafeac097ba51e1eab809c07102126bd5f8e5425","analyzedAt":"2026-08-21T22:01:08.818Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}