diff --git a/package.json b/package.json
index 7811865fb..ed54da445 100644
--- a/package.json
+++ b/package.json
@@ -24,10 +24,7 @@
     "smoke": "node tests/smoke/run"
   },
   "lint-staged": {
-    "*.js": [
-      "prettier --write \"**/*.{js,json}\"",
-      "git add"
-    ]
+    "*.js": ["prettier --write \"**/*.{js,json}\"", "git add"]
   },
   "author": {
     "name": "Algolia, Inc.",
@@ -80,15 +77,14 @@
   },
   "peerDependencies": {
     "react": "^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1",
-    "react-dom": "^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1"
+    "react-dom": "^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1",
+    "react-is": "^16.0.0"
   },
   "dependencies": {
     "@base2/pretty-print-object": "1.0.0",
     "is-plain-object": "3.0.1"
   },
   "jest": {
-    "setupFilesAfterEnv": [
-      "<rootDir>tests/setupTests.js"
-    ]
+    "setupFilesAfterEnv": ["<rootDir>tests/setupTests.js"]
   }
 }
diff --git a/src/index.spec.js b/src/index.spec.js
index c2b4c288c..985ae8065 100644
--- a/src/index.spec.js
+++ b/src/index.spec.js
@@ -2,7 +2,14 @@
 
 /* eslint-disable react/no-string-refs */
 
-import React, { Fragment, Component } from 'react';
+import React, {
+  Fragment,
+  Component,
+  Suspense,
+  createContext,
+  Profiler,
+  StrictMode,
+} from 'react';
 import { createRenderer } from 'react-test-renderer/shallow';
 import { mount } from 'enzyme';
 import reactElementToJSXString, { preserveFunctionLineBreak } from './index';
@@ -1113,6 +1120,53 @@ describe('reactElementToJSXString(ReactElement)', () => {
     ).toEqual(`<div render={<><div /><div /></>} />`);
   });
 
+  it('reactElementToJSXString(<Suspense fallback="loading" />)', () => {
+    expect(reactElementToJSXString(<Suspense fallback="loading" />)).toEqual(
+      `<Suspense fallback="loading" />`
+    );
+  });
+
+  it('reactElementToJSXString(<Profiler id="Main" />)', () => {
+    expect(reactElementToJSXString(<Profiler id="Main" />)).toEqual(
+      `<Profiler id="Main" />`
+    );
+  });
+
+  it('reactElementToJSXString(<StrictMode />)', () => {
+    expect(reactElementToJSXString(<StrictMode />)).toEqual(`<StrictMode />`);
+  });
+
+  it('reactElementToJSXString(<Context.Provider><Context.Consumer/></Context.Provider>)', () => {
+    const Context = createContext('Custom Context');
+    expect(
+      reactElementToJSXString(
+        <Context.Provider>
+          <Context.Consumer />
+        </Context.Provider>
+      )
+    ).toEqual(
+      `<Context.Provider>
+  <Context.Consumer />
+</Context.Provider>`
+    );
+  });
+
+  it('reactElementToJSXString: context with displayName', () => {
+    const Context = createContext('Custom Context');
+    Context.displayName = 'CustomContext';
+    expect(
+      reactElementToJSXString(
+        <Context.Provider>
+          <Context.Consumer />
+        </Context.Provider>
+      )
+    ).toEqual(
+      `<CustomContext.Provider>
+  <CustomContext.Consumer />
+</CustomContext.Provider>`
+    );
+  });
+
   it('should not cause recursive loop when prop object contains an element', () => {
     const Test = () => <div>Test</div>;
 
diff --git a/src/libs/getComponentNameFromType.js b/src/libs/getComponentNameFromType.js
new file mode 100644
index 000000000..a7c50b835
--- /dev/null
+++ b/src/libs/getComponentNameFromType.js
@@ -0,0 +1,121 @@
+/**
+ * Reference from https://github.com/facebook/react/blob/28625c6f45423e6edc5ca0e2932281769c0d431e/packages/shared/getComponentNameFromType.js
+ *
+ * @flow
+ */
+
+import type { Context } from 'react';
+import { Fragment } from 'react';
+import {
+  ContextConsumer,
+  ContextProvider,
+  ForwardRef,
+  Portal,
+  Memo,
+  Profiler,
+  StrictMode,
+  Suspense,
+  SuspenseList,
+  Lazy,
+} from 'react-is';
+
+/**
+ * didn't export the type in React
+ * same as https://github.com/facebook/react/blob/310187264d01a31bc3079358f13662d31a079d9e/packages/react/index.js
+ */
+type LazyComponent<T, P> = {
+  $$typeof: Symbol | number,
+  _payload: P,
+  _init: (payload: P) => T,
+};
+
+// Keep in sync with react-reconciler/getComponentNameFromFiber
+function getWrappedName(
+  outerType: mixed,
+  innerType: any,
+  wrapperName: string
+): string {
+  const displayName = (outerType: any).displayName;
+  if (displayName) {
+    return displayName;
+  }
+  const functionName = innerType.displayName || innerType.name || '';
+  return functionName !== '' ? `${wrapperName}(${functionName})` : wrapperName;
+}
+
+// Keep in sync with react-reconciler/getComponentNameFromFiber
+function getContextName(type: Context<any>) {
+  return type.displayName || 'Context';
+}
+
+// Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead.
+// eslint-disable-next-line complexity
+function getComponentNameFromType(type: mixed): string | null {
+  if (type === null || type === undefined) {
+    // Host root, text node or just invalid type.
+    return null;
+  }
+  if (typeof type === 'function') {
+    return (type: any).displayName || type.name || null;
+  }
+  if (typeof type === 'string') {
+    return type;
+  }
+  // eslint-disable-next-line default-case
+  switch (type) {
+    case Fragment:
+      return 'Fragment';
+    case Portal:
+      return 'Portal';
+    case Profiler:
+      return 'Profiler';
+    case StrictMode:
+      return 'StrictMode';
+    case Suspense:
+      return 'Suspense';
+    case SuspenseList:
+      return 'SuspenseList';
+    // case REACT_CACHE_TYPE:
+    //   return 'Cache';
+  }
+  if (typeof type === 'object') {
+    // eslint-disable-next-line default-case
+    switch (type.$$typeof) {
+      case ContextConsumer: {
+        /**
+         * in DEV, should get context from `_context`.
+         * https://github.com/facebook/react/blob/e16d61c3000e2de6217d06b9afad162e883f73c4/packages/react/src/ReactContext.js#L44-L125
+         */
+        const context: any = type._context ?? type;
+        return `${getContextName(context)}.Consumer`;
+      }
+      case ContextProvider: {
+        const context: any = type._context;
+        return `${getContextName(context)}.Provider`;
+      }
+      case ForwardRef:
+        // eslint-disable-next-line no-case-declarations
+        return getWrappedName(type, type.render, 'ForwardRef');
+      case Memo: {
+        const outerName = (type: any).displayName || null;
+        if (outerName !== null) {
+          return outerName;
+        }
+        return getComponentNameFromType(type.type) || 'Memo';
+      }
+      case Lazy: {
+        const lazyComponent: LazyComponent<any, any> = (type: any);
+        const payload = lazyComponent._payload;
+        const init = lazyComponent._init;
+        try {
+          return getComponentNameFromType(init(payload));
+        } catch (x) {
+          return null;
+        }
+      }
+    }
+  }
+  return null;
+}
+
+export default getComponentNameFromType;
diff --git a/src/parser/parseReactElement.js b/src/parser/parseReactElement.js
index 773b1a98d..f681a9b0f 100644
--- a/src/parser/parseReactElement.js
+++ b/src/parser/parseReactElement.js
@@ -9,15 +9,22 @@ import {
   createReactFragmentTreeNode,
 } from './../tree';
 import type { TreeNode } from './../tree';
+import getComponentNameFromType from '../libs/getComponentNameFromType';
 
 const supportFragment = Boolean(Fragment);
 
-const getReactElementDisplayName = (element: ReactElement<*>): string =>
-  element.type.displayName ||
-  (element.type.name !== '_default' ? element.type.name : null) || // function name
-  (typeof element.type === 'function' // function without a name, you should provide one
-    ? 'No Display Name'
-    : element.type);
+const getReactElementDisplayName = (element: ReactElement<*>): string => {
+  const displayName = getComponentNameFromType(element.type);
+  if (
+    displayName === '_default' ||
+    displayName === null ||
+    displayName === undefined
+  ) {
+    return 'No Display Name';
+  }
+
+  return displayName;
+};
 
 const noChildren = (propsValue, propName) => propName !== 'children';