@@ -2,7 +2,7 @@ use crate::{
2
2
canvas:: { Canvas , CanvasSubviewMut } ,
3
3
component:: { ComponentHelperExt , Components , InstantiatedComponent } ,
4
4
context:: { Context , ContextStack , SystemContext } ,
5
- element:: ElementExt ,
5
+ element:: { ElementExt , ElementKey } ,
6
6
props:: AnyProps ,
7
7
terminal:: { Terminal , TerminalEvents } ,
8
8
} ;
@@ -12,10 +12,10 @@ use std::{
12
12
any:: Any ,
13
13
cell:: { Ref , RefMut } ,
14
14
collections:: HashMap ,
15
- io:: { self , Write } ,
16
- mem,
15
+ io, mem,
17
16
} ;
18
17
use taffy:: { AvailableSpace , Layout , NodeId , Point , Size , Style , TaffyTree } ;
18
+ use uuid:: Uuid ;
19
19
20
20
pub ( crate ) struct UpdateContext < ' a > {
21
21
terminal : Option < & ' a mut Terminal > ,
@@ -120,13 +120,16 @@ impl<'a, 'b, 'c> ComponentUpdater<'a, 'b, 'c> {
120
120
. with_context ( context, |component_context_stack| {
121
121
let mut used_components = HashMap :: with_capacity ( self . children . components . len ( ) ) ;
122
122
123
+ let mut child_node_ids = Vec :: new ( ) ;
124
+
123
125
for mut child in children {
124
126
let mut component: InstantiatedComponent =
125
127
match self . children . components . remove ( child. key ( ) ) {
126
128
Some ( component)
127
129
if component. component ( ) . type_id ( )
128
130
== child. helper ( ) . component_type_id ( ) =>
129
131
{
132
+ child_node_ids. push ( component. node_id ( ) ) ;
130
133
component
131
134
}
132
135
_ => {
@@ -138,23 +141,25 @@ impl<'a, 'b, 'c> ComponentUpdater<'a, 'b, 'c> {
138
141
LayoutEngineNodeContext :: default ( ) ,
139
142
)
140
143
. expect ( "we should be able to add the node" ) ;
141
- self . context
142
- . layout_engine
143
- . add_child ( self . node_id , new_node_id)
144
- . expect ( "we should be able to add the child" ) ;
144
+ child_node_ids. push ( new_node_id) ;
145
145
let h = child. helper ( ) ;
146
146
InstantiatedComponent :: new ( new_node_id, child. props_mut ( ) , h)
147
147
}
148
148
} ;
149
149
component. update ( self . context , component_context_stack, child. props_mut ( ) ) ;
150
- if used_components
151
- . insert ( child. key ( ) . clone ( ) , component)
152
- . is_some ( )
153
- {
154
- panic ! ( "duplicate key for sibling components: {}" , child. key( ) ) ;
150
+
151
+ let mut child_key = child. key ( ) . clone ( ) ;
152
+ while used_components. contains_key ( & child_key) {
153
+ child_key = ElementKey :: new ( Uuid :: new_v4 ( ) . as_u128 ( ) ) ;
155
154
}
155
+ used_components. insert ( child_key, component) ;
156
156
}
157
157
158
+ self . context
159
+ . layout_engine
160
+ . set_children ( self . node_id , & child_node_ids)
161
+ . expect ( "we should be able to set the children" ) ;
162
+
158
163
for ( _, component) in self . children . components . drain ( ) {
159
164
self . context
160
165
. layout_engine
@@ -375,7 +380,6 @@ impl<'a> Tree<'a> {
375
380
break ;
376
381
}
377
382
}
378
- write ! ( term, "\r \n " ) ?;
379
383
Ok ( ( ) )
380
384
}
381
385
}
@@ -411,21 +415,45 @@ mod tests {
411
415
use macro_rules_attribute:: apply;
412
416
use smol_macros:: test;
413
417
418
+ #[ derive( Default , Props ) ]
419
+ struct MyInnerComponentProps {
420
+ label : String ,
421
+ }
422
+
423
+ #[ component]
424
+ fn MyInnerComponent (
425
+ mut hooks : Hooks ,
426
+ props : & MyInnerComponentProps ,
427
+ ) -> impl Into < AnyElement < ' static > > {
428
+ let mut counter = hooks. use_state ( || 0 ) ;
429
+ counter += 1 ;
430
+ element ! {
431
+ Text ( content: format!( "render count ({}): {}" , props. label, counter) )
432
+ }
433
+ }
434
+
414
435
#[ component]
415
436
fn MyComponent ( mut hooks : Hooks ) -> impl Into < AnyElement < ' static > > {
416
437
let mut system = hooks. use_context_mut :: < SystemContext > ( ) ;
417
- let mut counter = hooks. use_state ( || 0 ) ;
438
+ let mut tick = hooks. use_state ( || 0 ) ;
418
439
419
440
hooks. use_future ( async move {
420
- counter += 1 ;
441
+ tick += 1 ;
421
442
} ) ;
422
443
423
- if counter == 1 {
444
+ if tick == 1 {
424
445
system. exit ( ) ;
425
446
}
426
447
427
448
element ! {
428
- Text ( content: format!( "count: {}" , counter) )
449
+ Box ( flex_direction: FlexDirection :: Column ) {
450
+ Text ( content: format!( "tick: {}" , tick) )
451
+ MyInnerComponent ( label: "a" )
452
+ // without a key, these next elements may not be re-used across renders
453
+ #( ( 0 ..2 ) . map( |i| element! { MyInnerComponent ( label: format!( "b{}" , i) ) } ) )
454
+ // with a key, these next elements will definitely be re-used across renders
455
+ #( ( 0 ..2 ) . map( |i| element! { MyInnerComponent ( key: i, label: format!( "c{}" , i) ) } ) )
456
+ }
429
457
}
430
458
}
431
459
@@ -435,7 +463,10 @@ mod tests {
435
463
. await
436
464
. unwrap ( ) ;
437
465
let actual = canvases. iter ( ) . map ( |c| c. to_string ( ) ) . collect :: < Vec < _ > > ( ) ;
438
- let expected = vec ! [ "count: 0\n " , "count: 1\n " ] ;
466
+ let expected = vec ! [
467
+ "tick: 0\n render count (a): 1\n render count (b0): 1\n render count (b1): 1\n render count (c0): 1\n render count (c1): 1\n " ,
468
+ "tick: 1\n render count (a): 2\n render count (b0): 2\n render count (b1): 1\n render count (c0): 2\n render count (c1): 2\n " ,
469
+ ] ;
439
470
assert_eq ! ( actual, expected) ;
440
471
}
441
472
}
0 commit comments