11import React from 'react' ;
2+ import { polyfill } from 'react-lifecycles-compat' ;
23import T from 'prop-types' ;
34import { layout , select , behavior , event } from 'd3' ;
45import clone from 'clone' ;
@@ -10,9 +11,11 @@ import Node from '../Node';
1011import Link from '../Link' ;
1112import './style.css' ;
1213
13- export default class Tree extends React . Component {
14+ class Tree extends React . Component {
1415 state = {
15- data : this . assignInternalProperties ( clone ( this . props . data ) ) ,
16+ // eslint-disable-next-line react/no-unused-state
17+ dataRef : this . props . data ,
18+ data : Tree . assignInternalProperties ( clone ( this . props . data ) ) ,
1619 rd3tSvgClassName : `_${ uuid . v4 ( ) } ` ,
1720 rd3tGClassName : `_${ uuid . v4 ( ) } ` ,
1821 } ;
@@ -27,6 +30,19 @@ export default class Tree extends React.Component {
2730 } ,
2831 } ;
2932
33+ static getDerivedStateFromProps ( nextProps , prevState ) {
34+ // Clone new data & assign internal properties if `data` object reference changed.
35+ if ( nextProps . data !== prevState . dataRef ) {
36+ return {
37+ // eslint-disable-next-line react/no-unused-state
38+ dataRef : nextProps . data ,
39+ data : Tree . assignInternalProperties ( clone ( nextProps . data ) ) ,
40+ } ;
41+ }
42+
43+ return null ;
44+ }
45+
3046 constructor ( props ) {
3147 super ( props ) ;
3248 this . internalState . d3 = Tree . calculateD3Geometry ( this . props ) ;
@@ -38,8 +54,14 @@ export default class Tree extends React.Component {
3854 }
3955
4056 componentDidUpdate ( prevProps ) {
41- // Rebind zoom listeners to new DOM nodes in case NodeWrapper switched <TransitionGroup> <-> <g>
42- if ( prevProps . transitionDuration !== this . props . transitionDuration ) {
57+ // If zoom-specific props change -> rebind listener with new values
58+ // Or: rebind zoom listeners to new DOM nodes in case NodeWrapper switched <TransitionGroup> <-> <g>
59+ if (
60+ ! deepEqual ( this . props . translate , prevProps . translate ) ||
61+ ! deepEqual ( this . props . scaleExtent , prevProps . scaleExtent ) ||
62+ this . props . zoom !== prevProps . zoom ||
63+ this . props . transitionDuration !== prevProps . transitionDuration
64+ ) {
4365 this . bindZoomListener ( this . props ) ;
4466 }
4567
@@ -50,31 +72,11 @@ export default class Tree extends React.Component {
5072 translate : this . internalState . d3 . translate ,
5173 } ) ;
5274
75+ this . internalState . d3 = Tree . calculateD3Geometry ( this . props ) ;
5376 this . internalState . targetNode = null ;
5477 }
5578 }
5679
57- // eslint-disable-next-line camelcase
58- UNSAFE_componentWillReceiveProps ( nextProps ) {
59- // Clone new data & assign internal properties
60- if ( this . props . data !== nextProps . data ) {
61- this . setState ( {
62- data : this . assignInternalProperties ( clone ( nextProps . data ) ) ,
63- } ) ;
64- }
65-
66- this . internalState . d3 = Tree . calculateD3Geometry ( nextProps ) ;
67-
68- // If zoom-specific props change -> rebind listener with new values
69- if (
70- ! deepEqual ( this . props . translate , nextProps . translate ) ||
71- ! deepEqual ( this . props . scaleExtent , nextProps . scaleExtent ) ||
72- this . props . zoom !== nextProps . zoom
73- ) {
74- this . bindZoomListener ( nextProps ) ;
75- }
76- }
77-
7880 /**
7981 * setInitialTreeDepth - Description
8082 *
@@ -134,11 +136,12 @@ export default class Tree extends React.Component {
134136 * `data` set that are required for tree manipulation and returns
135137 * a new `data` array.
136138 *
139+ * @static
137140 * @param {array } data Hierarchical tree data
138141 *
139142 * @return {array } `data` array with internal properties added
140143 */
141- assignInternalProperties ( data ) {
144+ static assignInternalProperties ( data ) {
142145 // Wrap the root node into an array for recursive transformations if it wasn't in one already.
143146 const d = Array . isArray ( data ) ? data : [ data ] ;
144147 return d . map ( node => {
@@ -149,7 +152,7 @@ export default class Tree extends React.Component {
149152 }
150153 // If there are children, recursively assign properties to them too
151154 if ( node . children && node . children . length > 0 ) {
152- node . children = this . assignInternalProperties ( node . children ) ;
155+ node . children = Tree . assignInternalProperties ( node . children ) ;
153156 node . _children = node . children ;
154157 }
155158 return node ;
@@ -500,7 +503,6 @@ export default class Tree extends React.Component {
500503 } = this . props ;
501504 const { translate, scale } = this . internalState . d3 ;
502505 const subscriptions = { ...nodeSize , ...separation , depthFactor, initialDepth } ;
503-
504506 return (
505507 < div className = { `rd3t-tree-container ${ zoomable ? 'rd3t-grabbable' : undefined } ` } >
506508 < svg className = { rd3tSvgClassName } width = "100%" height = "100%" >
@@ -640,3 +642,8 @@ Tree.propTypes = {
640642 links : T . object ,
641643 } ) ,
642644} ;
645+
646+ // Polyfill React 16 lifecycle methods for compat with React 15.
647+ polyfill ( Tree ) ;
648+
649+ export default Tree ;
0 commit comments