mobxjs/mobx · error

It is not allowed to use shouldComponentUpdate in observer…

Error message

It is not allowed to use shouldComponentUpdate in observer based components.

What it means

In observer class components, mobx-react installs its own `observerSCU` as `shouldComponentUpdate` to control re-rendering based on the observer reaction. A user-defined SCU would conflict with (and defeat) that mechanism, so if an existing SCU differs from observerSCU (and the class isn't a PureComponent), the wrap is rejected.

Solutions

  1. Remove your custom `shouldComponentUpdate` and rely on the observer's fine-grained tracking, which only re-renders on observed data changes.
  2. If SCU logic must remain, drop `observer` for that component and use explicit `<Observer>` regions for observable access instead.
  3. If conditional rendering is needed, gate it inside `render` (e.g. compare props there) or use React.memo-equivalent props checks in a parent.

Example fix

// before
class Row extends React.Component {
  shouldComponentUpdate(nextProps) { return nextProps.id !== this.props.id }
  render() { return <div>{this.props.item.name}</div> }
}
export default observer(Row) // throws

// after
class Row extends React.Component {
  render() { return <div>{this.props.item.name}</div> }
}
export default observer(Row)
Defensive patterns

Strategy: validation

Validate before calling

if (typeof MyClass.prototype.shouldComponentUpdate === 'function' &&
    MyClass.prototype.shouldComponentUpdate.name !== 'observerSCU') {
  throw new Error('Remove custom shouldComponentUpdate before applying observer')
}

Type guard

const hasCustomScu = (c) => typeof c?.prototype?.shouldComponentUpdate === 'function' && c.prototype.shouldComponentUpdate.name !== 'observerSCU'

Try / catch

try {
  Observed = observer(MyClass)
} catch (e) {
  if (String(e.message).includes('shouldComponentUpdate')) {
    // remove custom SCU or drop observer; cannot auto-fix safely
  }
  throw e
}

Prevention

When it happens

Trigger: Defining `shouldComponentUpdate` on a class and then applying `observer` (the symbol check lets an inherited observerSCU pass, but any custom SCU throws); extending PureComponent is exempt, anything else with custom SCU is not.

Common situations: Hand-optimized shouldComponentUpdate implementations from pre-observer code being combined with @observer; copying performance-tuned class components into an observer-based codebase.

Related errors


AI-assisted analysis of mobxjs/mobx@01211a698b (2026-08-28). Data as JSON: /api/errors/6b9ac4579f16a797. Report an issue: GitHub.

Appendix: source

Thrown at packages/mobx-react/src/observerClass.ts:77

    if (componentClass[isMobXReactObserverSymbol]) {
        const displayName = getDisplayName(componentClass)
        throw new Error(
            `The provided component class (${displayName}) has already been declared as an observer component.`
        )
    } else {
        componentClass[isMobXReactObserverSymbol] = true
    }

    if (prototype.componentWillReact) {
        throw new Error("The componentWillReact life-cycle event is no longer supported")
    }
    if (componentClass["__proto__"] !== PureComponent) {
        if (!prototype.shouldComponentUpdate) {
            prototype.shouldComponentUpdate = observerSCU
        } else if (prototype.shouldComponentUpdate !== observerSCU) {
            // n.b. unequal check, instead of existence check, as @observer might be on superclass as well
            throw new Error(
                "It is not allowed to use shouldComponentUpdate in observer based components."
            )
        }
    }

    if (__DEV__) {
        Object.defineProperties(prototype, observablePropDescriptors)
    }

    const originalRender = prototype.render
    if (typeof originalRender !== "function") {
        const displayName = getDisplayName(componentClass)
        throw new Error(
            `[mobx-react] class component (${displayName}) is missing \`render\` method.` +
                `\n\`observer\` requires \`render\` being a function defined on prototype.` +
                `\n\`render = () => {}\` or \`render = function() {}\` is not supported.`
        )
    }

View on GitHub (pinned to 01211a698b)