Skip to content

Commit 2ac4544

Browse files
authored
Migrate Treemap and makeFlexible to functional components (#1358)
* Convert Treemap to a functional component * Update makeFlexible factory to make it create functional components * Add eslint-plugin-react-hooks and fix error in make-vis-flexible.js
1 parent c8ed350 commit 2ac4544

File tree

6 files changed

+65
-90
lines changed

6 files changed

+65
-90
lines changed

.eslintrc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22
"extends": [
33
"eslint:recommended",
44
"plugin:react/recommended",
5+
"plugin:react-hooks/recommended",
56
"plugin:jest/recommended",
67
"prettier",
78
"prettier/react"
89
],
910
"parser": "babel-eslint",
1011
"plugins": [
1112
"react",
13+
"react-hooks",
1214
"prettier",
1315
"babel",
1416
"jest"

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"eslint-plugin-babel": "^5.3.0",
3838
"eslint-plugin-prettier": "^3.1.3",
3939
"eslint-plugin-react": "^7.20.0",
40+
"eslint-plugin-react-hooks": "^4.0.4",
4041
"husky": "^1.1.2"
4142
},
4243
"husky": {

packages/react-vis/src/make-vis-flexible.js

Lines changed: 43 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,12 @@
1818
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1919
// THE SOFTWARE.
2020

21-
import React from 'react';
21+
import React, {useState, useEffect, useRef} from 'react';
2222
import window from 'global/window';
2323

2424
import XYPlot from 'plot/xy-plot';
2525
import {getDOMNode} from 'utils/react-utils';
2626

27-
const CONTAINER_REF = 'container';
28-
2927
// As a performance enhancement, we want to only listen once
3028
const resizeSubscribers = [];
3129
const DEBOUNCE_DURATION = 100;
@@ -101,79 +99,61 @@ function getDisplayName(Component) {
10199
*/
102100

103101
function makeFlexible(Component, isWidthFlexible, isHeightFlexible) {
104-
const ResultClass = class extends React.Component {
105-
static get propTypes() {
106-
const {height, width, ...otherPropTypes} = Component.propTypes; // eslint-disable-line no-unused-vars
107-
return otherPropTypes;
108-
}
109-
110-
constructor(props) {
111-
super(props);
112-
this.state = {
113-
height: 0,
114-
width: 0
115-
};
116-
}
117-
118-
/**
119-
* Get the width of the container and assign the width.
120-
* @private
121-
*/
122-
_onResize = () => {
123-
const containerElement = getDOMNode(this[CONTAINER_REF]);
124-
const {offsetHeight, offsetWidth} = containerElement;
102+
const ResultFunctionalComponent = function(props) {
103+
const containerRef = useRef();
125104

126-
const newHeight =
127-
this.state.height === offsetHeight ? {} : {height: offsetHeight};
105+
const [size, setSize] = useState({height: 0, width: 0});
128106

129-
const newWidth =
130-
this.state.width === offsetWidth ? {} : {width: offsetWidth};
107+
useEffect(() => {
108+
function _onResize() {
109+
const containerElement = getDOMNode(containerRef.current);
110+
const {offsetHeight, offsetWidth} = containerElement;
131111

132-
this.setState({
133-
...newHeight,
134-
...newWidth
135-
});
136-
};
112+
const newHeight =
113+
size.height === offsetHeight ? {} : {height: offsetHeight};
137114

138-
componentDidMount() {
139-
this._onResize();
140-
this.cancelSubscription = subscribeToDebouncedResize(this._onResize);
141-
}
115+
const newWidth = size.width === offsetWidth ? {} : {width: offsetWidth};
142116

143-
UNSAFE_componentWillReceiveProps() {
144-
this._onResize();
145-
}
117+
setSize(prevSize => ({
118+
...prevSize,
119+
...newHeight,
120+
...newWidth
121+
}));
122+
}
146123

147-
componentWillUnmount() {
148-
this.cancelSubscription();
149-
}
124+
const cancelSubscription = subscribeToDebouncedResize(_onResize);
150125

151-
render() {
152-
const {height, width} = this.state;
153-
const props = {
154-
...this.props,
155-
animation: height === 0 && width === 0 ? null : this.props.animation
126+
return () => {
127+
cancelSubscription();
156128
};
129+
}, [size.width, size.height]);
157130

158-
const updatedDimensions = {
159-
...(isHeightFlexible ? {height} : {}),
160-
...(isWidthFlexible ? {width} : {})
161-
};
131+
const {height, width} = size;
132+
const componentProps = {
133+
...props,
134+
animation: height === 0 && width === 0 ? null : props.animation
135+
};
162136

163-
return (
164-
<div
165-
ref={ref => (this[CONTAINER_REF] = ref)}
166-
style={{width: '100%', height: '100%'}}
167-
>
168-
<Component {...updatedDimensions} {...props} />
169-
</div>
170-
);
171-
}
137+
const updatedDimensions = {
138+
...(isHeightFlexible ? {height} : {}),
139+
...(isWidthFlexible ? {width} : {})
140+
};
141+
142+
return (
143+
<div ref={containerRef} style={{width: '100%', height: '100%'}}>
144+
<Component {...updatedDimensions} {...componentProps} />
145+
</div>
146+
);
172147
};
173148

174-
ResultClass.displayName = `Flexible${getDisplayName(Component)}`;
149+
const {height, width, ...otherPropTypes} = Component.propTypes || {}; // eslint-disable-line no-unused-vars
150+
ResultFunctionalComponent.propTypes = otherPropTypes;
151+
152+
ResultFunctionalComponent.displayName = `Flexible${getDisplayName(
153+
Component
154+
)}`;
175155

176-
return ResultClass;
156+
return ResultFunctionalComponent;
177157
}
178158

179159
export function makeHeightFlexible(component) {

packages/react-vis/src/treemap/index.js

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -91,30 +91,18 @@ function _getScaleFns(props) {
9191
};
9292
}
9393

94-
class Treemap extends React.Component {
95-
constructor(props) {
96-
super(props);
97-
this.state = {
98-
scales: _getScaleFns(props),
99-
...getInnerDimensions(props, props.margin)
100-
};
101-
}
102-
103-
UNSAFE_componentWillReceiveProps(props) {
104-
this.setState({
105-
scales: _getScaleFns(props),
106-
...getInnerDimensions(props, props.margin)
107-
});
108-
}
94+
function Treemap(props) {
95+
const scales = _getScaleFns(props);
96+
const innerDimensions = getInnerDimensions(props, props.margin);
10997

11098
/**
11199
* Create the list of nodes to render.
112100
* @returns {Array} Array of nodes.
113101
* @private
114102
*/
115-
_getNodesToRender() {
116-
const {innerWidth, innerHeight} = this.state;
117-
const {data, mode, padding, sortFunction, getSize} = this.props;
103+
function _getNodesToRender() {
104+
const {innerWidth, innerHeight} = innerDimensions;
105+
const {data, mode, padding, sortFunction, getSize} = props;
118106
if (!data) {
119107
return [];
120108
}
@@ -163,13 +151,11 @@ class Treemap extends React.Component {
163151
return treemapingFunction(structuredInput).descendants();
164152
}
165153

166-
render() {
167-
const {renderMode} = this.props;
168-
const {scales} = this.state;
169-
const nodes = this._getNodesToRender();
170-
const TreemapElement = renderMode === 'SVG' ? TreemapSVG : TreemapDOM;
171-
return <TreemapElement {...this.props} nodes={nodes} scales={scales} />;
172-
}
154+
const {renderMode} = props;
155+
const nodes = _getNodesToRender();
156+
const TreemapElement = renderMode === 'SVG' ? TreemapSVG : TreemapDOM;
157+
158+
return <TreemapElement {...props} nodes={nodes} scales={scales} />;
173159
}
174160

175161
Treemap.displayName = 'Treemap';

packages/showcase/showcase-links.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ export const SHOWCASE_LINKS = {
106106
HorizontalDiscreteColorLegendExample: `${SHOWCASE_BASE_URL}/legends/horizontal-discrete-color.js`,
107107
HorizontalDiscreteCustomPalette: `${SHOWCASE_BASE_URL}/legends/horizontal-discrete-custom-palette.js`,
108108
SearchableDiscreteColorLegendExample: `${SHOWCASE_BASE_URL}/legends/searchable-discrete-color.js`,
109+
// eslint-disable-next-line max-len
109110
SearchableDiscreteColorLegendHoverExample: `${SHOWCASE_BASE_URL}/legends/searchable-discrete-color-hover.js`,
110111
ContinuousColorLegendExample: `${SHOWCASE_BASE_URL}/legends/continuous-color.js`,
111112
ContinuousSizeLegendExample: `${SHOWCASE_BASE_URL}/legends/continuous-size.js'`

yarn.lock

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6603,6 +6603,11 @@ eslint-plugin-prettier@^3.1.3:
66036603
dependencies:
66046604
prettier-linter-helpers "^1.0.0"
66056605

6606+
eslint-plugin-react-hooks@^4.0.4:
6607+
version "4.0.4"
6608+
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.0.4.tgz#aed33b4254a41b045818cacb047b81e6df27fa58"
6609+
integrity sha512-equAdEIsUETLFNCmmCkiCGq6rkSK5MoJhXFPFYeUebcjKgBmWWcgVOqZyQC8Bv1BwVCnTq9tBxgJFgAJTWoJtA==
6610+
66066611
eslint-plugin-react@^6.7.1:
66076612
version "6.10.3"
66086613
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-6.10.3.tgz#c5435beb06774e12c7db2f6abaddcbf900cd3f78"
@@ -9557,10 +9562,10 @@ js-base64@^2.1.8, js-base64@^2.1.9:
95579562
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.2.tgz#313b6274dda718f714d00b3330bbae6e38e90209"
95589563
integrity sha1-MTtidN2nGPcU0AszMLuubjjpAgk=
95599564

9560-
js-beautify@^1.8.8:
9565+
js-beautify@1.10.3, js-beautify@^1.8.8:
95619566
version "1.10.3"
95629567
resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.10.3.tgz#c73fa10cf69d3dfa52d8ed624f23c64c0a6a94c1"
9563-
integrity sha1-xz+hDPadPfpS2O1iTyPGTApqlME=
9568+
integrity sha512-wfk/IAWobz1TfApSdivH5PJ0miIHgDoYb1ugSqHcODPmaYu46rYe5FVuIEkhjg8IQiv6rDNPyhsqbsohI/C2vQ==
95649569
dependencies:
95659570
config-chain "^1.1.12"
95669571
editorconfig "^0.15.3"

0 commit comments

Comments
 (0)