@@ -6,6 +6,7 @@ import withScrolling, {
66 createVerticalStrength ,
77 createHorizontalStrength ,
88} from 'react-dnd-scrollzone' ;
9+ import { polyfill } from 'react-lifecycles-compat' ;
910import 'react-virtualized/styles.css' ;
1011import TreeNode from './tree-node' ;
1112import NodeRendererDefault from './node-renderer-default' ;
@@ -108,6 +109,14 @@ class ReactSortableTree extends Component {
108109 searchMatches : [ ] ,
109110 searchFocusTreeIndex : null ,
110111 dragging : false ,
112+
113+ // props that need to be used in gDSFP or static functions will be stored here
114+ instanceProps : {
115+ treeData : [ ] ,
116+ ignoreOneTreeUpdate : false ,
117+ searchQuery : null ,
118+ searchFocusOffset : null ,
119+ } ,
111120 } ;
112121
113122 this . toggleChildrenVisibility = this . toggleChildrenVisibility . bind ( this ) ;
@@ -120,8 +129,15 @@ class ReactSortableTree extends Component {
120129 }
121130
122131 componentDidMount ( ) {
123- this . loadLazyChildren ( ) ;
124- this . search ( this . props ) ;
132+ ReactSortableTree . loadLazyChildren ( this . props , this . state ) ;
133+ const stateUpdate = ReactSortableTree . search (
134+ this . props ,
135+ this . state ,
136+ true ,
137+ true ,
138+ false
139+ ) ;
140+ this . setState ( stateUpdate ) ;
125141
126142 // Hook into react-dnd state changes to detect when the drag ends
127143 // TODO: This is very brittle, so it needs to be replaced if react-dnd
@@ -131,34 +147,49 @@ class ReactSortableTree extends Component {
131147 . subscribeToStateChange ( this . handleDndMonitorChange ) ;
132148 }
133149
134- componentWillReceiveProps ( nextProps ) {
135- if ( this . props . treeData !== nextProps . treeData ) {
136- // Ignore updates caused by search, in order to avoid infinite looping
137- if ( this . ignoreOneTreeUpdate ) {
138- this . ignoreOneTreeUpdate = false ;
139- } else {
140- // Reset the focused index if the tree has changed
141- this . setState ( { searchFocusTreeIndex : null } ) ;
150+ static getDerivedStateFromProps ( nextProps , prevState ) {
151+ const { instanceProps } = prevState ;
152+ const newState = { } ;
142153
143- // Load any children defined by a function
144- this . loadLazyChildren ( nextProps ) ;
154+ // make sure we have the most recent version of treeData
155+ instanceProps . treeData = nextProps . treeData ;
145156
146- this . search ( nextProps , false , false ) ;
157+ if ( ! isEqual ( instanceProps . treeData , nextProps . treeData ) ) {
158+ if ( instanceProps . ignoreOneTreeUpdate ) {
159+ instanceProps . ignoreOneTreeUpdate = false ;
160+ } else {
161+ newState . searchFocusTreeIndex = null ;
162+ ReactSortableTree . loadLazyChildren ( nextProps , prevState ) ;
163+ Object . assign (
164+ newState ,
165+ ReactSortableTree . search ( nextProps , prevState , false , false , false )
166+ ) ;
147167 }
148168
149- // Reset the drag state
150- this . setState ( {
151- draggingTreeData : null ,
152- draggedNode : null ,
153- draggedMinimumTreeIndex : null ,
154- draggedDepth : null ,
155- dragging : false ,
156- } ) ;
157- } else if ( ! isEqual ( this . props . searchQuery , nextProps . searchQuery ) ) {
158- this . search ( nextProps ) ;
159- } else if ( this . props . searchFocusOffset !== nextProps . searchFocusOffset ) {
160- this . search ( nextProps , true , true , true ) ;
169+ newState . draggingTreeData = null ;
170+ newState . draggedNode = null ;
171+ newState . draggedMinimumTreeIndex = null ;
172+ newState . draggedDepth = null ;
173+ newState . dragging = false ;
174+ } else if ( ! isEqual ( instanceProps . searchQuery , nextProps . searchQuery ) ) {
175+ Object . assign (
176+ newState ,
177+ ReactSortableTree . search ( nextProps , prevState , true , true , false )
178+ ) ;
179+ } else if (
180+ instanceProps . searchFocusOffset !== nextProps . searchFocusOffset
181+ ) {
182+ Object . assign (
183+ newState ,
184+ ReactSortableTree . search ( nextProps , prevState , true , true , true )
185+ ) ;
161186 }
187+
188+ instanceProps . searchQuery = nextProps . searchQuery ;
189+ instanceProps . searchFocusOffset = nextProps . searchFocusOffset ;
190+ newState . instanceProps = instanceProps ;
191+
192+ return newState ;
162193 }
163194
164195 // listen to dragging
@@ -197,8 +228,10 @@ class ReactSortableTree extends Component {
197228 }
198229
199230 toggleChildrenVisibility ( { node : targetNode , path } ) {
231+ const { instanceProps } = this . state ;
232+
200233 const treeData = changeNodeAtPath ( {
201- treeData : this . props . treeData ,
234+ treeData : instanceProps . treeData ,
202235 path,
203236 newNode : ( { node } ) => ( { ...node , expanded : ! node . expanded } ) ,
204237 getNodeKey : this . props . getNodeKey ,
@@ -250,46 +283,40 @@ class ReactSortableTree extends Component {
250283 } ) ;
251284 }
252285
253- search (
254- props = this . props ,
255- seekIndex = true ,
256- expand = true ,
257- singleSearch = false
258- ) {
286+ // returns the new state after search
287+ static search ( props , state , seekIndex , expand , singleSearch ) {
259288 const {
260- treeData,
261289 onChange,
290+ getNodeKey,
262291 searchFinishCallback,
263292 searchQuery,
264293 searchMethod,
265294 searchFocusOffset,
266295 onlyExpandSearchedNodes,
267296 } = props ;
268297
269- // Skip search if no conditions are specified
270- if (
271- ( searchQuery === null ||
272- typeof searchQuery === 'undefined' ||
273- String ( searchQuery ) === '' ) &&
274- ! searchMethod
275- ) {
276- this . setState ( {
277- searchMatches : [ ] ,
278- } ) ;
298+ const { instanceProps } = state ;
279299
300+ // Skip search if no conditions are specified
301+ if ( ! searchQuery && ! searchMethod ) {
280302 if ( searchFinishCallback ) {
281303 searchFinishCallback ( [ ] ) ;
282304 }
283305
284- return ;
306+ return { searchMatches : [ ] } ;
285307 }
286308
309+ const newState = { } ;
310+
287311 // if onlyExpandSearchedNodes collapse the tree and search
288312 const { treeData : expandedTreeData , matches : searchMatches } = find ( {
289- getNodeKey : this . props . getNodeKey ,
313+ getNodeKey,
290314 treeData : onlyExpandSearchedNodes
291- ? toggleExpandedForAll ( { treeData, expanded : false } )
292- : treeData ,
315+ ? toggleExpandedForAll ( {
316+ treeData : instanceProps . treeData ,
317+ expanded : false ,
318+ } )
319+ : instanceProps . treeData ,
293320 searchQuery,
294321 searchMethod : searchMethod || defaultSearchMethod ,
295322 searchFocusOffset,
@@ -299,7 +326,7 @@ class ReactSortableTree extends Component {
299326
300327 // Update the tree with data leaving all paths leading to matching nodes open
301328 if ( expand ) {
302- this . ignoreOneTreeUpdate = true ; // Prevents infinite loop
329+ newState . ignoreOneTreeUpdate = true ; // Prevents infinite loop
303330 onChange ( expandedTreeData ) ;
304331 }
305332
@@ -316,20 +343,20 @@ class ReactSortableTree extends Component {
316343 searchFocusTreeIndex = searchMatches [ searchFocusOffset ] . treeIndex ;
317344 }
318345
319- this . setState ( {
320- searchMatches ,
321- searchFocusTreeIndex ,
322- } ) ;
346+ newState . searchMatches = searchMatches ;
347+ newState . searchFocusTreeIndex = searchFocusTreeIndex ;
348+
349+ return newState ;
323350 }
324351
325352 startDrag ( { path } ) {
326- this . setState ( ( ) => {
353+ this . setState ( ( prevState ) => {
327354 const {
328355 treeData : draggingTreeData ,
329356 node : draggedNode ,
330357 treeIndex : draggedMinimumTreeIndex ,
331358 } = removeNode ( {
332- treeData : this . props . treeData ,
359+ treeData : prevState . instanceProps . treeData ,
333360 path,
334361 getNodeKey : this . props . getNodeKey ,
335362 } ) ;
@@ -349,6 +376,8 @@ class ReactSortableTree extends Component {
349376 depth : draggedDepth ,
350377 minimumTreeIndex : draggedMinimumTreeIndex ,
351378 } ) {
379+ const { instanceProps } = this . state ;
380+
352381 // Ignore this hover if it is at the same position as the last hover
353382 if (
354383 this . state . draggedDepth === draggedDepth &&
@@ -359,7 +388,8 @@ class ReactSortableTree extends Component {
359388
360389 // Fall back to the tree data if something is being dragged in from
361390 // an external element
362- const draggingTreeData = this . state . draggingTreeData || this . props . treeData ;
391+ const draggingTreeData =
392+ this . state . draggingTreeData || instanceProps . treeData ;
363393
364394 const addedResult = memoizedInsertNode ( {
365395 treeData : draggingTreeData ,
@@ -391,6 +421,8 @@ class ReactSortableTree extends Component {
391421 }
392422
393423 endDrag ( dropResult ) {
424+ const { instanceProps } = this . state ;
425+
394426 const resetTree = ( ) =>
395427 this . setState ( {
396428 draggingTreeData : null ,
@@ -415,13 +447,13 @@ class ReactSortableTree extends Component {
415447 } ) ;
416448 }
417449
418- let treeData = this . state . draggingTreeData || this . props . treeData ;
450+ let treeData = this . state . draggingTreeData || instanceProps . treeData ;
419451
420452 // If copying is enabled, a drop outside leaves behind a copy in the
421453 // source tree
422454 if ( shouldCopy ) {
423455 treeData = changeNodeAtPath ( {
424- treeData : this . props . treeData , // use treeData unaltered by the drag operation
456+ treeData : instanceProps . treeData , // use treeData unaltered by the drag operation
425457 path,
426458 newNode : ( { node : copyNode } ) => ( { ...copyNode } ) , // create a shallow copy of the node
427459 getNodeKey : this . props . getNodeKey ,
@@ -448,10 +480,13 @@ class ReactSortableTree extends Component {
448480 }
449481
450482 // Load any children in the tree that are given by a function
451- loadLazyChildren ( props = this . props ) {
483+ // calls the onChange callback on the new treeData
484+ static loadLazyChildren ( props , state ) {
485+ const { instanceProps } = state ;
486+
452487 walk ( {
453- treeData : props . treeData ,
454- getNodeKey : this . props . getNodeKey ,
488+ treeData : instanceProps . treeData ,
489+ getNodeKey : props . getNodeKey ,
455490 callback : ( { node, path, lowerSiblingCounts, treeIndex } ) => {
456491 // If the node has children defined by a function, and is either expanded
457492 // or set to load even before expansion, run the function.
@@ -469,9 +504,9 @@ class ReactSortableTree extends Component {
469504
470505 // Provide a helper to append the new data when it is received
471506 done : childrenArray =>
472- this . props . onChange (
507+ props . onChange (
473508 changeNodeAtPath ( {
474- treeData : this . props . treeData ,
509+ treeData : instanceProps . treeData ,
475510 path,
476511 newNode : ( { node : oldNode } ) =>
477512 // Only replace the old node if it's the one we set off to find children
@@ -482,7 +517,7 @@ class ReactSortableTree extends Component {
482517 children : childrenArray ,
483518 }
484519 : oldNode ,
485- getNodeKey : this . props . getNodeKey ,
520+ getNodeKey : props . getNodeKey ,
486521 } )
487522 ) ,
488523 } ) ;
@@ -492,9 +527,11 @@ class ReactSortableTree extends Component {
492527 }
493528
494529 renderRow (
495- { node , parentNode , path , lowerSiblingCounts , treeIndex } ,
530+ row ,
496531 { listIndex, style, getPrevRow, matchKeys, swapFrom, swapDepth, swapLength }
497532 ) {
533+ const { node, parentNode, path, lowerSiblingCounts, treeIndex } = row ;
534+
498535 const {
499536 canDrag,
500537 generateNodeProps,
@@ -572,9 +609,10 @@ class ReactSortableTree extends Component {
572609 draggedNode,
573610 draggedDepth,
574611 draggedMinimumTreeIndex,
612+ instanceProps,
575613 } = this . state ;
576614
577- const treeData = this . state . draggingTreeData || this . props . treeData ;
615+ const treeData = this . state . draggingTreeData || instanceProps . treeData ;
578616
579617 let rows ;
580618 let swapFrom = null ;
@@ -870,6 +908,8 @@ ReactSortableTree.contextTypes = {
870908 dragDropManager : PropTypes . shape ( { } ) ,
871909} ;
872910
911+ polyfill ( ReactSortableTree ) ;
912+
873913// Export the tree component without the react-dnd DragDropContext,
874914// for when component is used with other components using react-dnd.
875915// see: https://github.com/gaearon/react-dnd/issues/186
0 commit comments