Skip to content

Commit 414cf62

Browse files
rolandszokesolkimicreb
authored andcommitted
fix(displayname): refactor memo wrapper on functional components
Add Readme for React Dev Tools
1 parent 52f3ff3 commit 414cf62

4 files changed

Lines changed: 144 additions & 66 deletions

File tree

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,32 @@ This is not necessary if you use React Router 4.4+. You can find more details an
407407
</details>
408408
<p></p>
409409

410+
<details>
411+
<summary>Usage with React Developer Tools.</summary>
412+
<p></p>
413+
414+
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.
415+
416+
```jsx
417+
import React from 'react';
418+
import { view, store } from 'react-easy-state';
419+
import Table from 'rc-table';
420+
import cloneDeep from 'lodash/cloneDeep';
421+
422+
const user = store({
423+
name: 'Rick',
424+
});
425+
426+
const componentName = () => (
427+
<div>{user.name}</div>
428+
);
429+
430+
export default view(componentName);
431+
```
432+
433+
</details>
434+
<p></p>
435+
410436
<details>
411437
<summary>Passing nested data to third party components.</summary>
412438
<p></p>

__tests__/staticProps.test.js

Lines changed: 0 additions & 63 deletions
This file was deleted.

__tests__/staticProps.test.jsx

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/* eslint-disable react/forbid-foreign-prop-types */
2+
/* eslint-disable no-multi-assign */
3+
import React, { Component } from 'react';
4+
import { render, cleanup } from '@testing-library/react/pure';
5+
// eslint-disable-next-line import/no-unresolved
6+
import { view } from 'react-easy-state';
7+
import PropTypes from 'prop-types';
8+
9+
describe('static props', () => {
10+
afterEach(cleanup);
11+
12+
test('view() should proxy defaultProps for class components', () => {
13+
class MyCustomCompName extends Component {
14+
render() {
15+
return <div>{this.props.name}</div>;
16+
}
17+
}
18+
19+
MyCustomCompName.defaultProps = {
20+
name: 'Bob',
21+
};
22+
23+
const WrappedComp = view(MyCustomCompName);
24+
const { container } = render(<WrappedComp />);
25+
expect(container).toHaveTextContent('Bob');
26+
});
27+
28+
test('view() should proxy defaultProps for functional components', () => {
29+
const MyCustomCompName = props => {
30+
return <div>{props.name}</div>;
31+
};
32+
33+
MyCustomCompName.defaultProps = {
34+
name: 'Bob',
35+
};
36+
37+
const WrappedComp = view(MyCustomCompName);
38+
const { container } = render(<WrappedComp />);
39+
expect(container).toHaveTextContent('Bob');
40+
});
41+
42+
test('view() should proxy propTypes for class components', () => {
43+
class MyCustomCompName extends Component {
44+
render() {
45+
return <div>{this.props.name}</div>;
46+
}
47+
}
48+
49+
MyCustomCompName.propTypes = {
50+
name: PropTypes.string.isRequired,
51+
};
52+
53+
const ViewComp = view(MyCustomCompName);
54+
55+
const errorSpy = jest
56+
.spyOn(console, 'error')
57+
.mockImplementation(message =>
58+
expect(message.indexOf('Failed prop type')).not.toBe(-1),
59+
);
60+
render(<ViewComp number="Bob" />);
61+
expect(errorSpy).toHaveBeenCalled();
62+
errorSpy.mockRestore();
63+
});
64+
65+
test('view() should proxy propTypes for functional components', () => {
66+
const MyCustomCompName = props => {
67+
return <div>{props.number}</div>;
68+
};
69+
70+
MyCustomCompName.propTypes = {
71+
number: PropTypes.number.isRequired,
72+
};
73+
74+
const ViewComp = view(MyCustomCompName);
75+
76+
const errorSpy = jest
77+
.spyOn(console, 'error')
78+
.mockImplementation(message =>
79+
expect(message.indexOf('Failed prop type')).not.toBe(-1),
80+
);
81+
render(<ViewComp number="Bob" />);
82+
expect(errorSpy).toHaveBeenCalled();
83+
errorSpy.mockRestore();
84+
});
85+
86+
test('view() should proxy static methods', () => {
87+
class Comp extends Component {
88+
static getDerivedStateFromError() {}
89+
90+
static customMethod() {}
91+
}
92+
93+
const ViewComp = view(Comp);
94+
expect(ViewComp.getDerivedStateFromError).toBe(
95+
Comp.getDerivedStateFromError,
96+
);
97+
expect(ViewComp.customMethod).toBe(Comp.customMethod);
98+
});
99+
100+
test('view() should proxy static getters', () => {
101+
class Comp extends Component {
102+
static get defaultProp() {
103+
return { key: 'value' };
104+
}
105+
106+
static get customProp() {
107+
return { key: 'hello' };
108+
}
109+
}
110+
111+
const ViewComp = view(Comp);
112+
expect(ViewComp.defaultProps).toEqual(Comp.defaultProps);
113+
expect(ViewComp.customProp).toEqual(Comp.customProp);
114+
});
115+
});

src/view.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,6 @@ export function view(Comp) {
7474
isInsideFunctionComponent = false;
7575
}
7676
};
77-
ReactiveComp.displayName = Comp.displayName || Comp.name;
78-
ReactiveComp = memo(ReactiveComp);
7977
} else {
8078
const BaseComp = isStatelessComp ? Component : Comp;
8179
// a HOC which overwrites render, shouldComponentUpdate and componentWillUnmount
@@ -170,5 +168,7 @@ export function view(Comp) {
170168
});
171169
}
172170

173-
return ReactiveComp;
171+
return isStatelessComp && hasHooks
172+
? memo(ReactiveComp)
173+
: ReactiveComp;
174174
}

0 commit comments

Comments
 (0)