1111 */
1212
1313import { Key } from '@react-types/shared' ;
14- import { useMemo , useState } from 'react' ;
14+ import { useState } from 'react' ;
1515
1616export interface TreeOptions < T extends object > {
1717 /** Initial root items in the tree. */
@@ -126,44 +126,47 @@ export function useTreeData<T extends object>(options: TreeOptions<T>): TreeData
126126 getKey = ( item : any ) => item . id || item . key ,
127127 getChildren = ( item : any ) => item . children
128128 } = options ;
129- let map = useMemo ( ( ) => new Map < Key , TreeNode < T > > ( ) , [ ] ) ;
130129
131130 // We only want to compute this on initial render.
132- // eslint-disable-next-line react-hooks/exhaustive-deps
133- let initialNodes = useMemo ( ( ) => buildTree ( initialItems ) , [ ] ) ;
134- let [ items , setItems ] = useState ( initialNodes ) ;
131+ let [ tree , setItems ] = useState < { items : TreeNode < T > [ ] , nodeMap : Map < Key , TreeNode < T > > } > ( ( ) => buildTree ( initialItems , new Map ( ) ) ) ;
132+ let { items , nodeMap } = tree ;
133+
135134 let [ selectedKeys , setSelectedKeys ] = useState ( new Set < Key > ( initialSelectedKeys || [ ] ) ) ;
136135
137- function buildTree ( initialItems : T [ ] = [ ] , parentKey ?: Key | null ) {
138- return initialItems . map ( item => {
139- let node : TreeNode < T > = {
140- key : getKey ( item ) ,
141- parentKey : parentKey ,
142- value : item ,
143- children : null
144- } ;
136+ function buildTree ( initialItems : T [ ] = [ ] , map : Map < Key , TreeNode < T > > , parentKey ?: Key | null ) {
137+ return {
138+ items : initialItems . map ( item => {
139+ let node : TreeNode < T > = {
140+ key : getKey ( item ) ,
141+ parentKey : parentKey ,
142+ value : item ,
143+ children : null
144+ } ;
145145
146- node . children = buildTree ( getChildren ( item ) , node . key ) ;
147- map . set ( node . key , node ) ;
148- return node ;
149- } ) ;
146+ node . children = buildTree ( getChildren ( item ) , map , node . key ) . items ;
147+ map . set ( node . key , node ) ;
148+ return node ;
149+ } ) ,
150+ nodeMap : map
151+ } ;
150152 }
151153
152- function updateTree ( items : TreeNode < T > [ ] , key : Key , update : ( node : TreeNode < T > ) => TreeNode < T > ) {
153- let node = map . get ( key ) ;
154+ function updateTree ( items : TreeNode < T > [ ] , key : Key , update : ( node : TreeNode < T > ) => TreeNode < T > , originalMap : Map < Key , TreeNode < T > > ) {
155+ let node = originalMap . get ( key ) ;
154156 if ( ! node ) {
155- return items ;
157+ return { items, nodeMap : originalMap } ;
156158 }
159+ let map = new Map < Key , TreeNode < T > > ( originalMap ) ;
157160
158161 // Create a new node. If null, then delete the node, otherwise replace.
159162 let newNode = update ( node ) ;
160163 if ( newNode == null ) {
161- deleteNode ( node ) ;
164+ deleteNode ( node , map ) ;
162165 } else {
163- addNode ( newNode ) ;
166+ addNode ( newNode , map ) ;
164167 }
165168
166- // Walk up the tree and update each parent to refer to the new chilren .
169+ // Walk up the tree and update each parent to refer to the new children .
167170 while ( node . parentKey ) {
168171 let nextParent = map . get ( node . parentKey ) ;
169172 let copy : TreeNode < T > = {
@@ -196,26 +199,29 @@ export function useTreeData<T extends object>(options: TreeOptions<T>): TreeData
196199 items = items . filter ( c => c !== node ) ;
197200 }
198201
199- return items . map ( item => {
200- if ( item === node ) {
201- return newNode ;
202- }
202+ return {
203+ items : items . map ( item => {
204+ if ( item === node ) {
205+ return newNode ;
206+ }
203207
204- return item ;
205- } ) ;
208+ return item ;
209+ } ) ,
210+ nodeMap : map
211+ } ;
206212 }
207213
208- function addNode ( node : TreeNode < T > ) {
214+ function addNode ( node : TreeNode < T > , map : Map < Key , TreeNode < T > > ) {
209215 map . set ( node . key , node ) ;
210216 for ( let child of node . children ) {
211- addNode ( child ) ;
217+ addNode ( child , map ) ;
212218 }
213219 }
214220
215- function deleteNode ( node : TreeNode < T > ) {
221+ function deleteNode ( node : TreeNode < T > , map : Map < Key , TreeNode < T > > ) {
216222 map . delete ( node . key ) ;
217223 for ( let child of node . children ) {
218- deleteNode ( child ) ;
224+ deleteNode ( child , map ) ;
219225 }
220226 }
221227
@@ -224,19 +230,22 @@ export function useTreeData<T extends object>(options: TreeOptions<T>): TreeData
224230 selectedKeys,
225231 setSelectedKeys,
226232 getItem ( key : Key ) {
227- return map . get ( key ) ;
233+ return nodeMap . get ( key ) ;
228234 } ,
229235 insert ( parentKey : Key | null , index : number , ...values : T [ ] ) {
230- setItems ( items => {
231- let nodes = buildTree ( values , parentKey ) ;
236+ setItems ( ( { items, nodeMap : originalMap } ) => {
237+ let { items : newNodes , nodeMap : newMap } = buildTree ( values , originalMap , parentKey ) ;
232238
233239 // If parentKey is null, insert into the root.
234240 if ( parentKey == null ) {
235- return [
236- ...items . slice ( 0 , index ) ,
237- ...nodes ,
238- ...items . slice ( index )
239- ] ;
241+ return {
242+ items : [
243+ ...items . slice ( 0 , index ) ,
244+ ...newNodes ,
245+ ...items . slice ( index )
246+ ] ,
247+ nodeMap : newMap
248+ } ;
240249 }
241250
242251 // Otherwise, update the parent node and its ancestors.
@@ -246,30 +255,30 @@ export function useTreeData<T extends object>(options: TreeOptions<T>): TreeData
246255 value : parentNode . value ,
247256 children : [
248257 ...parentNode . children . slice ( 0 , index ) ,
249- ...nodes ,
258+ ...newNodes ,
250259 ...parentNode . children . slice ( index )
251260 ]
252- } ) ) ;
261+ } ) , newMap ) ;
253262 } ) ;
254263 } ,
255264 insertBefore ( key : Key , ...values : T [ ] ) : void {
256- let node = map . get ( key ) ;
265+ let node = nodeMap . get ( key ) ;
257266 if ( ! node ) {
258267 return ;
259268 }
260269
261- let parentNode = map . get ( node . parentKey ) ;
270+ let parentNode = nodeMap . get ( node . parentKey ) ;
262271 let nodes = parentNode ? parentNode . children : items ;
263272 let index = nodes . indexOf ( node ) ;
264273 this . insert ( parentNode ?. key , index , ...values ) ;
265274 } ,
266275 insertAfter ( key : Key , ...values : T [ ] ) : void {
267- let node = map . get ( key ) ;
276+ let node = nodeMap . get ( key ) ;
268277 if ( ! node ) {
269278 return ;
270279 }
271280
272- let parentNode = map . get ( node . parentKey ) ;
281+ let parentNode = nodeMap . get ( node . parentKey ) ;
273282 let nodes = parentNode ? parentNode . children : items ;
274283 let index = nodes . indexOf ( node ) ;
275284 this . insert ( parentNode ?. key , index + 1 , ...values ) ;
@@ -281,7 +290,7 @@ export function useTreeData<T extends object>(options: TreeOptions<T>): TreeData
281290 if ( parentKey == null ) {
282291 this . insert ( null , items . length , ...values ) ;
283292 } else {
284- let parentNode = map . get ( parentKey ) ;
293+ let parentNode = nodeMap . get ( parentKey ) ;
285294 if ( ! parentNode ) {
286295 return ;
287296 }
@@ -290,16 +299,24 @@ export function useTreeData<T extends object>(options: TreeOptions<T>): TreeData
290299 }
291300 } ,
292301 remove ( ...keys : Key [ ] ) {
302+ if ( keys . length === 0 ) {
303+ return ;
304+ }
305+
293306 let newItems = items ;
307+ let prevMap = nodeMap ;
308+ let newTree ;
294309 for ( let key of keys ) {
295- newItems = updateTree ( newItems , key , ( ) => null ) ;
310+ newTree = updateTree ( newItems , key , ( ) => null , prevMap ) ;
311+ prevMap = newTree . nodeMap ;
312+ newItems = newTree . items ;
296313 }
297314
298- setItems ( newItems ) ;
315+ setItems ( newTree ) ;
299316
300317 let selection = new Set ( selectedKeys ) ;
301318 for ( let key of selectedKeys ) {
302- if ( ! map . has ( key ) ) {
319+ if ( ! newTree . nodeMap . has ( key ) ) {
303320 selection . delete ( key ) ;
304321 }
305322 }
@@ -310,13 +327,14 @@ export function useTreeData<T extends object>(options: TreeOptions<T>): TreeData
310327 this . remove ( ...selectedKeys ) ;
311328 } ,
312329 move ( key : Key , toParentKey : Key | null , index : number ) {
313- setItems ( items => {
314- let node = map . get ( key ) ;
330+ setItems ( ( { items, nodeMap : originalMap } ) => {
331+ let node = originalMap . get ( key ) ;
315332 if ( ! node ) {
316- return items ;
333+ return { items, nodeMap : originalMap } ;
317334 }
318335
319- items = updateTree ( items , key , ( ) => null ) ;
336+ let { items : newItems , nodeMap : newMap } = updateTree ( items , key , ( ) => null , originalMap ) ;
337+
320338
321339 const movedNode = {
322340 ...node ,
@@ -325,15 +343,15 @@ export function useTreeData<T extends object>(options: TreeOptions<T>): TreeData
325343
326344 // If parentKey is null, insert into the root.
327345 if ( toParentKey == null ) {
328- return [
329- ...items . slice ( 0 , index ) ,
346+ return { items : [
347+ ...newItems . slice ( 0 , index ) ,
330348 movedNode ,
331- ...items . slice ( index )
332- ] ;
349+ ...newItems . slice ( index )
350+ ] , nodeMap : newMap } ;
333351 }
334352
335353 // Otherwise, update the parent node and its ancestors.
336- return updateTree ( items , toParentKey , parentNode => ( {
354+ return updateTree ( newItems , toParentKey , parentNode => ( {
337355 key : parentNode . key ,
338356 parentKey : parentNode . parentKey ,
339357 value : parentNode . value ,
@@ -342,21 +360,22 @@ export function useTreeData<T extends object>(options: TreeOptions<T>): TreeData
342360 movedNode ,
343361 ...parentNode . children . slice ( index )
344362 ]
345- } ) ) ;
363+ } ) , newMap ) ;
346364 } ) ;
347365 } ,
348366 update ( oldKey : Key , newValue : T ) {
349- setItems ( items => updateTree ( items , oldKey , oldNode => {
367+ setItems ( ( { items, nodeMap : originalMap } ) => updateTree ( items , oldKey , oldNode => {
350368 let node : TreeNode < T > = {
351369 key : oldNode . key ,
352370 parentKey : oldNode . parentKey ,
353371 value : newValue ,
354372 children : null
355373 } ;
356374
357- node . children = buildTree ( getChildren ( newValue ) , node . key ) ;
375+ let tree = buildTree ( getChildren ( newValue ) , originalMap , node . key ) ;
376+ node . children = tree . items ;
358377 return node ;
359- } ) ) ;
378+ } , originalMap ) ) ;
360379 }
361380 } ;
362381}
0 commit comments