@@ -6,6 +6,7 @@ import withScrolling, {
6
6
createVerticalStrength ,
7
7
createHorizontalStrength ,
8
8
} from 'react-dnd-scrollzone' ;
9
+ import { polyfill } from 'react-lifecycles-compat' ;
9
10
import 'react-virtualized/styles.css' ;
10
11
import TreeNode from './tree-node' ;
11
12
import NodeRendererDefault from './node-renderer-default' ;
@@ -108,6 +109,14 @@ class ReactSortableTree extends Component {
108
109
searchMatches : [ ] ,
109
110
searchFocusTreeIndex : null ,
110
111
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
+ } ,
111
120
} ;
112
121
113
122
this . toggleChildrenVisibility = this . toggleChildrenVisibility . bind ( this ) ;
@@ -120,8 +129,15 @@ class ReactSortableTree extends Component {
120
129
}
121
130
122
131
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 ) ;
125
141
126
142
// Hook into react-dnd state changes to detect when the drag ends
127
143
// TODO: This is very brittle, so it needs to be replaced if react-dnd
@@ -131,34 +147,49 @@ class ReactSortableTree extends Component {
131
147
. subscribeToStateChange ( this . handleDndMonitorChange ) ;
132
148
}
133
149
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 = { } ;
142
153
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 ;
145
156
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
+ ) ;
147
167
}
148
168
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
+ ) ;
161
186
}
187
+
188
+ instanceProps . searchQuery = nextProps . searchQuery ;
189
+ instanceProps . searchFocusOffset = nextProps . searchFocusOffset ;
190
+ newState . instanceProps = instanceProps ;
191
+
192
+ return newState ;
162
193
}
163
194
164
195
// listen to dragging
@@ -197,8 +228,10 @@ class ReactSortableTree extends Component {
197
228
}
198
229
199
230
toggleChildrenVisibility ( { node : targetNode , path } ) {
231
+ const { instanceProps } = this . state ;
232
+
200
233
const treeData = changeNodeAtPath ( {
201
- treeData : this . props . treeData ,
234
+ treeData : instanceProps . treeData ,
202
235
path,
203
236
newNode : ( { node } ) => ( { ...node , expanded : ! node . expanded } ) ,
204
237
getNodeKey : this . props . getNodeKey ,
@@ -250,46 +283,40 @@ class ReactSortableTree extends Component {
250
283
} ) ;
251
284
}
252
285
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 ) {
259
288
const {
260
- treeData,
261
289
onChange,
290
+ getNodeKey,
262
291
searchFinishCallback,
263
292
searchQuery,
264
293
searchMethod,
265
294
searchFocusOffset,
266
295
onlyExpandSearchedNodes,
267
296
} = props ;
268
297
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 ;
279
299
300
+ // Skip search if no conditions are specified
301
+ if ( ! searchQuery && ! searchMethod ) {
280
302
if ( searchFinishCallback ) {
281
303
searchFinishCallback ( [ ] ) ;
282
304
}
283
305
284
- return ;
306
+ return { searchMatches : [ ] } ;
285
307
}
286
308
309
+ const newState = { } ;
310
+
287
311
// if onlyExpandSearchedNodes collapse the tree and search
288
312
const { treeData : expandedTreeData , matches : searchMatches } = find ( {
289
- getNodeKey : this . props . getNodeKey ,
313
+ getNodeKey,
290
314
treeData : onlyExpandSearchedNodes
291
- ? toggleExpandedForAll ( { treeData, expanded : false } )
292
- : treeData ,
315
+ ? toggleExpandedForAll ( {
316
+ treeData : instanceProps . treeData ,
317
+ expanded : false ,
318
+ } )
319
+ : instanceProps . treeData ,
293
320
searchQuery,
294
321
searchMethod : searchMethod || defaultSearchMethod ,
295
322
searchFocusOffset,
@@ -299,7 +326,7 @@ class ReactSortableTree extends Component {
299
326
300
327
// Update the tree with data leaving all paths leading to matching nodes open
301
328
if ( expand ) {
302
- this . ignoreOneTreeUpdate = true ; // Prevents infinite loop
329
+ newState . ignoreOneTreeUpdate = true ; // Prevents infinite loop
303
330
onChange ( expandedTreeData ) ;
304
331
}
305
332
@@ -316,20 +343,20 @@ class ReactSortableTree extends Component {
316
343
searchFocusTreeIndex = searchMatches [ searchFocusOffset ] . treeIndex ;
317
344
}
318
345
319
- this . setState ( {
320
- searchMatches ,
321
- searchFocusTreeIndex ,
322
- } ) ;
346
+ newState . searchMatches = searchMatches ;
347
+ newState . searchFocusTreeIndex = searchFocusTreeIndex ;
348
+
349
+ return newState ;
323
350
}
324
351
325
352
startDrag ( { path } ) {
326
- this . setState ( ( ) => {
353
+ this . setState ( ( prevState ) => {
327
354
const {
328
355
treeData : draggingTreeData ,
329
356
node : draggedNode ,
330
357
treeIndex : draggedMinimumTreeIndex ,
331
358
} = removeNode ( {
332
- treeData : this . props . treeData ,
359
+ treeData : prevState . instanceProps . treeData ,
333
360
path,
334
361
getNodeKey : this . props . getNodeKey ,
335
362
} ) ;
@@ -349,6 +376,8 @@ class ReactSortableTree extends Component {
349
376
depth : draggedDepth ,
350
377
minimumTreeIndex : draggedMinimumTreeIndex ,
351
378
} ) {
379
+ const { instanceProps } = this . state ;
380
+
352
381
// Ignore this hover if it is at the same position as the last hover
353
382
if (
354
383
this . state . draggedDepth === draggedDepth &&
@@ -359,7 +388,8 @@ class ReactSortableTree extends Component {
359
388
360
389
// Fall back to the tree data if something is being dragged in from
361
390
// an external element
362
- const draggingTreeData = this . state . draggingTreeData || this . props . treeData ;
391
+ const draggingTreeData =
392
+ this . state . draggingTreeData || instanceProps . treeData ;
363
393
364
394
const addedResult = memoizedInsertNode ( {
365
395
treeData : draggingTreeData ,
@@ -391,6 +421,8 @@ class ReactSortableTree extends Component {
391
421
}
392
422
393
423
endDrag ( dropResult ) {
424
+ const { instanceProps } = this . state ;
425
+
394
426
const resetTree = ( ) =>
395
427
this . setState ( {
396
428
draggingTreeData : null ,
@@ -415,13 +447,13 @@ class ReactSortableTree extends Component {
415
447
} ) ;
416
448
}
417
449
418
- let treeData = this . state . draggingTreeData || this . props . treeData ;
450
+ let treeData = this . state . draggingTreeData || instanceProps . treeData ;
419
451
420
452
// If copying is enabled, a drop outside leaves behind a copy in the
421
453
// source tree
422
454
if ( shouldCopy ) {
423
455
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
425
457
path,
426
458
newNode : ( { node : copyNode } ) => ( { ...copyNode } ) , // create a shallow copy of the node
427
459
getNodeKey : this . props . getNodeKey ,
@@ -448,10 +480,13 @@ class ReactSortableTree extends Component {
448
480
}
449
481
450
482
// 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
+
452
487
walk ( {
453
- treeData : props . treeData ,
454
- getNodeKey : this . props . getNodeKey ,
488
+ treeData : instanceProps . treeData ,
489
+ getNodeKey : props . getNodeKey ,
455
490
callback : ( { node, path, lowerSiblingCounts, treeIndex } ) => {
456
491
// If the node has children defined by a function, and is either expanded
457
492
// or set to load even before expansion, run the function.
@@ -469,9 +504,9 @@ class ReactSortableTree extends Component {
469
504
470
505
// Provide a helper to append the new data when it is received
471
506
done : childrenArray =>
472
- this . props . onChange (
507
+ props . onChange (
473
508
changeNodeAtPath ( {
474
- treeData : this . props . treeData ,
509
+ treeData : instanceProps . treeData ,
475
510
path,
476
511
newNode : ( { node : oldNode } ) =>
477
512
// Only replace the old node if it's the one we set off to find children
@@ -482,7 +517,7 @@ class ReactSortableTree extends Component {
482
517
children : childrenArray ,
483
518
}
484
519
: oldNode ,
485
- getNodeKey : this . props . getNodeKey ,
520
+ getNodeKey : props . getNodeKey ,
486
521
} )
487
522
) ,
488
523
} ) ;
@@ -492,9 +527,11 @@ class ReactSortableTree extends Component {
492
527
}
493
528
494
529
renderRow (
495
- { node , parentNode , path , lowerSiblingCounts , treeIndex } ,
530
+ row ,
496
531
{ listIndex, style, getPrevRow, matchKeys, swapFrom, swapDepth, swapLength }
497
532
) {
533
+ const { node, parentNode, path, lowerSiblingCounts, treeIndex } = row ;
534
+
498
535
const {
499
536
canDrag,
500
537
generateNodeProps,
@@ -572,9 +609,10 @@ class ReactSortableTree extends Component {
572
609
draggedNode,
573
610
draggedDepth,
574
611
draggedMinimumTreeIndex,
612
+ instanceProps,
575
613
} = this . state ;
576
614
577
- const treeData = this . state . draggingTreeData || this . props . treeData ;
615
+ const treeData = this . state . draggingTreeData || instanceProps . treeData ;
578
616
579
617
let rows ;
580
618
let swapFrom = null ;
@@ -870,6 +908,8 @@ ReactSortableTree.contextTypes = {
870
908
dragDropManager : PropTypes . shape ( { } ) ,
871
909
} ;
872
910
911
+ polyfill ( ReactSortableTree ) ;
912
+
873
913
// Export the tree component without the react-dnd DragDropContext,
874
914
// for when component is used with other components using react-dnd.
875
915
// see: https://github.com/gaearon/react-dnd/issues/186
0 commit comments