mobxjs/mobx · error
[mobx-react] `observer(${displayName}).componentDidMount` mu
Error message
[mobx-react] `observer(${displayName}).componentDidMount` must be defined on prototype.
`componentDidMount = () => {}` or `componentDidMount = function() {}` is not supported. What it means
mobx-react replaces componentDidMount on class components wrapped with observer() so it can start its reaction on mount. The replacement checks at mount time that the instance's componentDidMount is still the prototype one; if the component defined componentDidMount as an instance arrow function or instance function property, it shadows the patched prototype method and mobx-react throws. Instance property methods are incompatible because mobx-react must bind and control the lifecycle method itself.
Source
Thrown at packages/mobx-react/src/observerClass.ts:113
}
prototype.render = function () {
Object.defineProperty(this, "render", {
// There is no safe way to replace render, therefore it's forbidden.
configurable: false,
writable: false,
value: isUsingStaticRendering()
? originalRender
: createReactiveRender.call(this, originalRender)
})
return this.render()
}
const originalComponentDidMount = prototype.componentDidMount
prototype.componentDidMount = function () {
if (__DEV__ && this.componentDidMount !== Object.getPrototypeOf(this).componentDidMount) {
const displayName = getDisplayName(componentClass)
throw new Error(
`[mobx-react] \`observer(${displayName}).componentDidMount\` must be defined on prototype.` +
`\n\`componentDidMount = () => {}\` or \`componentDidMount = function() {}\` is not supported.`
)
}
// `componentDidMount` may not be called at all. React can abandon the instance after `render`.
// That's why we use finalization registry to dispose reaction created during render.
// Happens with `<Suspend>` see #3492
//
// `componentDidMount` can be called immediately after `componentWillUnmount` without calling `render` in between.
// Happens with `<StrictMode>`see #3395.
//
// If `componentDidMount` is called, it's guaranteed to run synchronously with render (similary to `useLayoutEffect`).
// Therefore we don't have to worry about external (observable) state being updated before mount (no state version checking).
//
// Things may change: "In the future, React will provide a feature that lets components preserve state between unmounts"
const admin = getAdministration(this)View on GitHub (pinned to 01211a698b)
Solutions
- Convert componentDidMount from a class-field arrow function to a regular prototype method: `componentDidMount() { ... }`
- Bind callbacks inside the constructor or at call sites instead of relying on arrow-function class fields for lifecycle methods
- If an instance method is truly needed, call super-equivalent logic via the prototype: define it as a prototype method
- Temporarily suppress by not using observer() and using <Observer> render-prop instead, but prefer fixing the method definition
Example fix
// before
class MyComponent extends React.Component {
componentDidMount = () => {
this.doStuff()
}
}
// after
class MyComponent extends React.Component {
componentDidMount() {
this.doStuff()
}
} Defensive patterns
Strategy: validation
Validate before calling
// in component constructor (dev check)
if (process.env.NODE_ENV !== 'production' && Object.prototype.hasOwnProperty.call(this, 'componentDidMount')) {
throw new Error('componentDidMount must be a prototype method, not a class-field arrow function')
} Type guard
function hasPrototypeComponentDidMount(ctor: Function): boolean {
return typeof ctor.prototype?.componentDidMount === 'function' ||
Object.getOwnPropertyNames(ctor.prototype).includes('componentDidMount')
} Try / catch
null
Prevention
- Never define React lifecycle methods as arrow-function class fields in observer() classes
- Enable ESLint rules (e.g. react/sort-comp or a custom rule) flagging instance lifecycle properties
- Bind in constructor instead of arrow fields when autobinding is needed
- Wrap classes with observer() early in development to catch this at mount
When it happens
Trigger: Defining `componentDidMount = () => {...}` or `componentDidMount = function() {...}` as a class field (instance property) inside a class that is wrapped with observer(), then mounting the component in __DEV__ mode.
Common situations: Class components written in modern class-fields style (or converted from hooks) where all methods are arrow functions for autobinding; TypeScript projects using `useDefineForClassFields` semantics; migrating a component to observer() without converting componentDidMount to a prototype method.
Related errors
- The componentWillReact life-cycle event is no longer support
- [mobx-react-lite] You are trying to use `observer` on a func
- [mobx-react-lite] `render` property of ForwardRef was not a
- The provided component class (${displayName}) has already be
- It is not allowed to use shouldComponentUpdate in observer b
AI-assisted analysis of mobxjs/mobx@01211a698b (2026-08-28).
Data as JSON: /api/errors/f2f64ea12999fb4d.
Report an issue: GitHub.