mobx: displayName not working in React 17 with observer

Intended outcome:

In this old issue (https://github.com/mobxjs/mobx/issues/141) it states the below should work. Also In the docs it states it will be fixed in React 17.

export const MyComponent2 = observer(() => "hello2!");
MyComponent2.displayName = "MyComponent2";

Is this an issue with observer now and/or should the docs be updated to say displayName does not work with observer?

Actual outcome: Viewing β€œReact DevTools” in CodeSandbox notice _c3 for the MyComponent2 name:

Screen Shot 2021-01-18 at 8 37 06 AM

How to reproduce the issue: https://codesandbox.io/s/mobx-displayname-reat-17-z61pb?file=/src/MyComponent.jsx

Versions

  • mobx: 6.0.4
  • mobx-react: 7.0.5
  • react: 17.0.1
  • react-dom: 17.0.1

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 23 (9 by maintainers)

Most upvoted comments

TL;DR

React v17 support set memo displayName, but only can set displayName once!

Code analysis

packages/react/src/ReactMemo.js

  if (__DEV__) {
    let ownName;
    Object.defineProperty(elementType, 'displayName', {
      enumerable: false,
      configurable: true,
      get: function() {
        return ownName;
      },
      set: function(name) {
        ownName = name;
        if (type.displayName == null) {  πŸ‘ˆπŸ»   // This is why !
          type.displayName = name;
        }
      },
    });
  }

You can only set displayName once.

      set: function(name) {
-        ownName = name;
-        if (type.displayName == null) {
-          type.displayName = name;
+        if (typeof name === 'string') {
+          ownName = name;
+          type.displayName = name; 
+        } else {
+          console.error(
+            'React component\'s displayName must be a string, %o is invalid',
+            name
          );
        }
      },

I rebuild react to solve it πŸ‘‰ https://codesandbox.io/s/mobx-displayname-reat-17-forked-gfyx3

<div style="display:flex;justify-content:center;width=650px;">

</div>

Expected Devtools Shown

<div style="display:flex;justify-content:center;width=650px;">

</div>

React displayName

React version 17.0.1 πŸ‘‰ https://codesandbox.io/s/react-17-memo-displayname-forked-yk4u0

<div style="display:flex;justify-content:center;width=650px;">

</div>

Can react component set displayName multiple times ?

  1. React.forwardRef πŸ‘Œ
  2. Normal Function Component πŸ‘Œ
  3. Class Component πŸ‘Œ
  4. React.memo πŸ™…β€β™‚οΈ

React component and mobx-react

packages/mobx-react-lite/src/observer.ts

export function observer<P extends object, TRef = {}>(
    baseComponent: React.RefForwardingComponent<TRef, P> | React.FunctionComponent<P>,
    options?: IObserverOptions
) {
    if (isUsingStaticRendering()) {
        return baseComponent
    }
    const realOptions = {
        forwardRef: false,
        ...options
    }
    const baseComponentName = baseComponent.displayName || baseComponent.name
    const wrappedComponent = (props: P, ref: React.Ref<TRef>) => {
        return useObserver(() => baseComponent(props, ref), baseComponentName)
    }
    wrappedComponent.displayName = baseComponentName  πŸ‘ˆπŸ»   // set displayName once
    if (realOptions.forwardRef) {
        memoComponent = memo(forwardRef(wrappedComponent))
    } else {
        memoComponent = memo(wrappedComponent)
    }
    copyStaticProperties(baseComponent, memoComponent)
    memoComponent.displayName = baseComponentName  πŸ‘ˆπŸ»   // set displayName twice
    return memoComponent
}

So you can’t change memo component’s displayName now.

export const MyComponent2 = observer(() => "hello2!");
MyComponent2.displayName = "MyComponent2";  πŸ‘ˆπŸ»   // not work

Previous Try

// swap these ?
- copyStaticProperties(baseComponent, memoComponent) 
+ copyStaticProperties(memoComponent, baseComponent) 
 memoComponent.displayName = baseComponentName 

This solution is not useful, cause mobx-react didn’t do anything wrong. πŸ˜„

Final Conclusion

I will create a PR for facebook/react soon , but not sure it will be accepted.

Hope my analysis is useful for you.

Thanks for creating the PR in facebook/react, hopefully, they will process it soon-ish.

by the way, can you invite me to join mobxjs github organization, I wanna be a long term mobxjs contributor.

We are generally promoting based on as-needed basis, not based on people desires πŸ˜ƒ Just continue to be active for now and when you need elevated permissions, you will get them.