diff --git a/README.md b/README.md
index 8e4f6df..3820fe9 100644
--- a/README.md
+++ b/README.md
@@ -407,6 +407,32 @@ This is not necessary if you use React Router 4.4+. You can find more details an
+
+Usage with React Developer Tools.
+
+
+If you want React Developer Tools to recognize your reactive view components with names, you have to pass a **named component** to the `view` wrapper function instead of an anonymous one.
+
+```jsx
+import React from 'react';
+import { view, store } from 'react-easy-state';
+import Table from 'rc-table';
+import cloneDeep from 'lodash/cloneDeep';
+
+const user = store({
+ name: 'Rick',
+});
+
+const componentName = () => (
+ {user.name}
+);
+
+export default view(componentName);
+```
+
+
+
+
Passing nested data to third party components.
diff --git a/__tests__/staticProps.test.js b/__tests__/staticProps.test.js
deleted file mode 100644
index ddd9151..0000000
--- a/__tests__/staticProps.test.js
+++ /dev/null
@@ -1,63 +0,0 @@
-/* eslint-disable react/forbid-foreign-prop-types */
-/* eslint-disable no-multi-assign */
-import { Component } from 'react';
-// eslint-disable-next-line import/no-unresolved
-import { view } from 'react-easy-state';
-
-describe('static props', () => {
- test('view() should proxy static properties from wrapped components', () => {
- class Comp extends Component {}
- function FuncComp() {}
-
- Comp.displayName = FuncComp.displayName = 'Name';
- Comp.contextTypes = FuncComp.contextTypes = {};
- Comp.propTypes = FuncComp.propTypes = {};
- Comp.defaultProps = FuncComp.defaultProps = {};
- Comp.customProp = FuncComp.customProp = {};
-
- const ViewComp = view(Comp);
- const ViewFuncComp = view(FuncComp);
-
- expect(ViewComp.displayName).toBe(Comp.displayName);
- expect(ViewComp.contextTypes).toBe(Comp.contextTypes);
- expect(ViewComp.propTypes).toBe(Comp.propTypes);
- expect(ViewComp.defaultProps).toBe(Comp.defaultProps);
- expect(ViewComp.customProp).toBe(Comp.customProp);
-
- expect(ViewFuncComp.displayName).toBe(FuncComp.displayName);
- expect(ViewFuncComp.contextTypes).toBe(FuncComp.contextTypes);
- expect(ViewFuncComp.propTypes).toBe(FuncComp.propTypes);
- expect(ViewFuncComp.defaultProps).toBe(FuncComp.defaultProps);
- expect(ViewFuncComp.customProp).toBe(FuncComp.customProp);
- });
-
- test('view() should proxy static methods', () => {
- class Comp extends Component {
- static getDerivedStateFromError() {}
-
- static customMethod() {}
- }
-
- const ViewComp = view(Comp);
- expect(ViewComp.getDerivedStateFromError).toBe(
- Comp.getDerivedStateFromError,
- );
- expect(ViewComp.customMethod).toBe(Comp.customMethod);
- });
-
- test('view() should proxy static getters', () => {
- class Comp extends Component {
- static get defaultProp() {
- return { key: 'value' };
- }
-
- static get customProp() {
- return { key: 'hello' };
- }
- }
-
- const ViewComp = view(Comp);
- expect(ViewComp.defaultProps).toEqual(Comp.defaultProps);
- expect(ViewComp.customProp).toEqual(Comp.customProp);
- });
-});
diff --git a/__tests__/staticProps.test.jsx b/__tests__/staticProps.test.jsx
new file mode 100644
index 0000000..2902854
--- /dev/null
+++ b/__tests__/staticProps.test.jsx
@@ -0,0 +1,115 @@
+/* eslint-disable react/forbid-foreign-prop-types */
+/* eslint-disable no-multi-assign */
+import React, { Component } from 'react';
+import { render, cleanup } from '@testing-library/react/pure';
+// eslint-disable-next-line import/no-unresolved
+import { view } from 'react-easy-state';
+import PropTypes from 'prop-types';
+
+describe('static props', () => {
+ afterEach(cleanup);
+
+ test('view() should proxy defaultProps for class components', () => {
+ class MyCustomCompName extends Component {
+ render() {
+ return {this.props.name}
;
+ }
+ }
+
+ MyCustomCompName.defaultProps = {
+ name: 'Bob',
+ };
+
+ const WrappedComp = view(MyCustomCompName);
+ const { container } = render();
+ expect(container).toHaveTextContent('Bob');
+ });
+
+ test('view() should proxy defaultProps for functional components', () => {
+ const MyCustomCompName = props => {
+ return {props.name}
;
+ };
+
+ MyCustomCompName.defaultProps = {
+ name: 'Bob',
+ };
+
+ const WrappedComp = view(MyCustomCompName);
+ const { container } = render();
+ expect(container).toHaveTextContent('Bob');
+ });
+
+ test('view() should proxy propTypes for class components', () => {
+ class MyCustomCompName extends Component {
+ render() {
+ return {this.props.name}
;
+ }
+ }
+
+ MyCustomCompName.propTypes = {
+ name: PropTypes.string.isRequired,
+ };
+
+ const ViewComp = view(MyCustomCompName);
+
+ const errorSpy = jest
+ .spyOn(console, 'error')
+ .mockImplementation(message =>
+ expect(message.indexOf('Failed prop type')).not.toBe(-1),
+ );
+ render();
+ expect(errorSpy).toHaveBeenCalled();
+ errorSpy.mockRestore();
+ });
+
+ test('view() should proxy propTypes for functional components', () => {
+ const MyCustomCompName = props => {
+ return {props.number}
;
+ };
+
+ MyCustomCompName.propTypes = {
+ number: PropTypes.number.isRequired,
+ };
+
+ const ViewComp = view(MyCustomCompName);
+
+ const errorSpy = jest
+ .spyOn(console, 'error')
+ .mockImplementation(message =>
+ expect(message.indexOf('Failed prop type')).not.toBe(-1),
+ );
+ render();
+ expect(errorSpy).toHaveBeenCalled();
+ errorSpy.mockRestore();
+ });
+
+ test('view() should proxy static methods', () => {
+ class Comp extends Component {
+ static getDerivedStateFromError() {}
+
+ static customMethod() {}
+ }
+
+ const ViewComp = view(Comp);
+ expect(ViewComp.getDerivedStateFromError).toBe(
+ Comp.getDerivedStateFromError,
+ );
+ expect(ViewComp.customMethod).toBe(Comp.customMethod);
+ });
+
+ test('view() should proxy static getters', () => {
+ class Comp extends Component {
+ static get defaultProp() {
+ return { key: 'value' };
+ }
+
+ static get customProp() {
+ return { key: 'hello' };
+ }
+ }
+
+ const ViewComp = view(Comp);
+ expect(ViewComp.defaultProps).toEqual(Comp.defaultProps);
+ expect(ViewComp.customProp).toEqual(Comp.customProp);
+ });
+});
diff --git a/src/view.js b/src/view.js
index 73ca6ea..fa919b3 100644
--- a/src/view.js
+++ b/src/view.js
@@ -74,8 +74,6 @@ export function view(Comp) {
isInsideFunctionComponent = false;
}
};
- ReactiveComp.displayName = Comp.displayName || Comp.name;
- ReactiveComp = memo(ReactiveComp);
} else {
const BaseComp = isStatelessComp ? Component : Comp;
// a HOC which overwrites render, shouldComponentUpdate and componentWillUnmount
@@ -170,5 +168,7 @@ export function view(Comp) {
});
}
- return ReactiveComp;
+ return isStatelessComp && hasHooks
+ ? memo(ReactiveComp)
+ : ReactiveComp;
}