{"record":{"id":"b05a9fb6e3ab5736","repo":"mobxjs/mobx","slug":"mobx-react-lite-you-are-trying-to-use-observer","errorCode":null,"errorMessage":"[mobx-react-lite] You are trying to use `observer` on a function component wrapped in either another `observer` or `React.memo`. The observer already applies 'React.memo' for you.","messagePattern":"\\[mobx-react-lite\\] You are trying to use `observer` on a function component wrapped in either another `observer` or `React\\.memo`\\. The observer already applies 'React\\.memo' for you\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/mobx-react-lite/src/observer.ts","lineNumber":43,"sourceCode":"): React.FunctionComponent<P> & React.MemoExoticComponent<React.FunctionComponent<P>>\n\nexport function observer<P extends object, TRef = {}>(\n    baseComponent: React.ForwardRefExoticComponent<\n        React.PropsWithoutRef<P> & React.RefAttributes<TRef>\n    >\n): React.MemoExoticComponent<\n    React.ForwardRefExoticComponent<React.PropsWithoutRef<P> & React.RefAttributes<TRef>>\n>\n\n// n.b. base case is not used for actual typings or exported in the typing files\nexport function observer<P extends object, TRef = {}>(\n    baseComponent:\n        | React.ForwardRefRenderFunction<TRef, P>\n        | React.FunctionComponent<P>\n        | React.ForwardRefExoticComponent<React.PropsWithoutRef<P> & React.RefAttributes<TRef>>\n) {\n    if (ReactMemoSymbol && baseComponent[\"$$typeof\"] === ReactMemoSymbol) {\n        throw new Error(\n            `[mobx-react-lite] You are trying to use \\`observer\\` on a function component wrapped in either another \\`observer\\` or \\`React.memo\\`. The observer already applies 'React.memo' for you.`\n        )\n    }\n\n    // The working of observer is explained step by step in this talk: https://www.youtube.com/watch?v=cPF4iBedoF0&feature=youtu.be&t=1307\n    if (isUsingStaticRendering()) {\n        return baseComponent\n    }\n\n    let useForwardRef = false\n    let render = baseComponent\n\n    const baseComponentName = baseComponent.displayName || baseComponent.name\n\n    // If already wrapped with forwardRef, unwrap,\n    // so we can patch render and apply memo\n    if (ReactForwardRefSymbol && baseComponent[\"$$typeof\"] === ReactForwardRefSymbol) {\n        useForwardRef = true","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/mobxjs/mobx/blob/01211a698b64ea94de8e5f276ff8235fcf8ddf96/packages/mobx-react-lite/src/observer.ts#L25-L61","documentation":"mobx-react-lite's `observer` already wraps the component in React.memo, so double-wrapping breaks the optimization and is rejected. This throw fires when the passed component's `$$typeof` equals `ReactMemoSymbol`, i.e. the input is a memoized component — which is exactly what `observer(...)` returns or what `React.memo(...)` produces. It is a developer-time contract check to prevent nested memo wrappers.","triggerScenarios":"Calling `observer(React.memo(Component))` or `observer(observer(Component))` — any function component whose `$$typeof` is `Symbol(react.memo)`.","commonSituations":"Incrementally migrating from manual React.memo to observer; composing HOCs in a pipeline where a component was already wrapped with observer; copy-pasting a memoized component into an observer call.","solutions":["Pass the plain function component to `observer` and remove the outer `React.memo` — observer applies memoization itself.","If wrapping multiple concerns with other HOCs, apply `observer` to the raw component and let other HOCs wrap the observer result.","If you receive an already-observed component, use it directly instead of re-wrapping with `observer`."],"exampleFix":"// before\nconst Cmp = React.memo(function MyComp(props) { return <div>{props.x}</div> })\nexport default observer(Cmp)\n\n// after\nfunction MyComp(props) { return <div>{props.x}</div> }\nexport default observer(MyComp)","handlingStrategy":"validation","validationCode":"function isMemoWrapped(Cmp) {\n  return Cmp && Cmp.$$typeof === Symbol.for('react.memo')\n}\n// before wrapping:\nif (isMemoWrapped(Base)) Base = Base.type // unwrap memo before observer(Base)\nobserver(Base)","typeGuard":"const isMemoComponent = (c) => !!c && typeof c === 'object' && c.$$typeof === Symbol.for('react.memo')","tryCatchPattern":null,"preventionTips":["Never wrap components in React.memo yourself when using mobx-react-lite — observer memoizes automatically.","Keep HOC pipelines ordered: observer applied only once, closest to the raw component.","Add a lint/CI check or helper wrapper that asserts the input is a plain function component."],"tags":["react","mobx-react-lite","observer","memo","api-misuse"],"backgroundTag":"double-memo-observer-wrap","analyzedSha":"01211a698b64ea94de8e5f276ff8235fcf8ddf96","analyzedAt":"2026-08-28T22:10:08.831Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}