1
- import { memo } from " react" ;
1
+ import { memo } from ' react' ;
2
2
import { createRoot } from 'react-dom/client' ;
3
3
import { createSignal , useSelector } from "react-tagged-state" ;
4
4
5
+ const random = ( max ) => Math . round ( Math . random ( ) * 1000 ) % max ;
6
+
5
7
const A = [ "pretty" , "large" , "big" , "small" , "tall" , "short" , "long" , "handsome" , "plain" , "quaint" , "clean" ,
6
8
"elegant" , "easy" , "angry" , "crazy" , "helpful" , "mushy" , "odd" , "unsightly" , "adorable" , "important" , "inexpensive" ,
7
9
"cheap" , "expensive" , "fancy" ] ;
8
10
const C = [ "red" , "yellow" , "blue" , "green" , "pink" , "brown" , "purple" , "brown" , "white" , "black" , "orange" ] ;
9
11
const N = [ "table" , "chair" , "house" , "bbq" , "desk" , "car" , "pony" , "cookie" , "sandwich" , "burger" , "pizza" , "mouse" ,
10
12
"keyboard" ] ;
11
13
12
- const random = ( max ) => Math . round ( Math . random ( ) * 1000 ) % max ;
13
-
14
14
let nextId = 1 ;
15
15
16
16
const buildData = ( count ) => {
17
- const res = new Array ( count ) ;
17
+ const data = new Array ( count ) ;
18
18
19
- for ( let index = 0 ; index < count ; index ++ ) {
20
- res [ index ] = {
19
+ for ( let i = 0 ; i < count ; i ++ ) {
20
+ data [ i ] = {
21
21
id : nextId ++ ,
22
- labelSignal : createSignal ( `${ A [ random ( A . length ) ] } ${ C [ random ( C . length ) ] } ${ N [ random ( N . length ) ] } ` ) ,
23
- isSelectedSignal : createSignal ( false )
22
+ label : `${ A [ random ( A . length ) ] } ${ C [ random ( C . length ) ] } ${ N [ random ( N . length ) ] } ` ,
24
23
} ;
25
24
}
26
25
27
- return res ;
28
- }
29
-
30
- const dataSignal = createSignal ( [ ] ) ;
31
-
32
- let selectedSignal = createSignal ( null ) ;
33
-
34
- const select = ( item ) => {
35
- selectedSignal ( ( prev ) => {
36
- if ( prev ) {
37
- prev . isSelectedSignal ( false ) ;
38
- }
39
-
40
- if ( item ) {
41
- item . isSelectedSignal ( true ) ;
42
- }
43
-
44
- return item ;
45
- } ) ;
26
+ return data ;
46
27
} ;
47
28
48
- const run = ( ) => {
49
- dataSignal ( buildData ( 1000 ) ) ;
50
- select ( null ) ;
51
- } ;
29
+ const data = createSignal ( [ ] ) ;
52
30
53
- const runLots = ( ) => {
54
- dataSignal ( buildData ( 10000 ) ) ;
55
- select ( null ) ;
56
- } ;
57
-
58
- const add = ( ) => {
59
- dataSignal ( ( curr ) => curr . concat ( buildData ( 1000 ) ) ) ;
60
- } ;
31
+ const selected = createSignal ( 0 ) ;
61
32
62
- const update = ( ) => {
63
- const items = dataSignal ( ) ;
33
+ const Row = memo ( ( { item } ) => {
34
+ const isSelected = useSelector ( selected , ( curr ) => curr === item . id ) ;
64
35
65
- for ( let index = 0 ; index < items . length ; index += 10 ) {
66
- items [ index ] . labelSignal ( ( labelSignal ) => labelSignal + " !!!" ) ;
67
- }
68
- } ;
69
-
70
- const clear = ( ) => {
71
- dataSignal ( [ ] ) ;
72
- select ( null ) ;
73
- } ;
74
-
75
- const swap = ( ) => {
76
- dataSignal ( ( curr ) => [ curr [ 0 ] , curr [ 998 ] , ...curr . slice ( 2 , 998 ) , curr [ 1 ] , curr [ 999 ] ] ) ;
77
- } ;
78
-
79
- const remove = ( id ) => dataSignal ( ( curr ) => curr . filter ( ( item ) => item . id !== id ) ) ;
80
-
81
- const GlyphIcon = (
82
- < span className = "glyphicon glyphicon-remove" aria-hidden = "true" />
83
- ) ;
84
-
85
- const SelectableRow = ( { isSelectedSignal, children} ) => (
86
- < tr className = { useSelector ( isSelectedSignal ) ? "danger" : "" } >
87
- { children }
88
- </ tr >
89
- ) ;
90
-
91
- const Label = ( { labelSignal} ) => useSelector ( labelSignal ) ;
92
-
93
- const ListItem = memo ( ( { item} ) => (
94
- < SelectableRow isSelectedSignal = { item . isSelectedSignal } >
36
+ return < tr className = { isSelected ? "danger" : "" } >
95
37
< td className = "col-md-1" > { item . id } </ td >
96
38
< td className = "col-md-4" >
97
- < a onClick = { ( ) => select ( item ) } > < Label labelSignal = { item . labelSignal } /> </ a >
39
+ < a onClick = { ( ) => selected ( item . id ) } > { item . label } </ a >
98
40
</ td >
99
41
< td className = "col-md-1" >
100
- < a onClick = { ( ) => remove ( item . id ) } > { GlyphIcon } </ a >
42
+ < a onClick = { ( ) => data ( ( curr ) => {
43
+ const idx = curr . findIndex ( ( d ) => d . id === item . id ) ;
44
+
45
+ return [ ...curr . slice ( 0 , idx ) , ...curr . slice ( idx + 1 ) ] ;
46
+ } ) } >
47
+ < span className = "glyphicon glyphicon-remove" aria-hidden = "true" />
48
+ </ a >
101
49
</ td >
102
50
< td className = "col-md-6" />
103
- </ SelectableRow >
104
- ) ) ;
51
+ </ tr >
52
+ } )
105
53
106
- const List = ( ) => {
107
- const items = useSelector ( dataSignal ) ;
54
+ const Rows = ( ) => {
55
+ const items = useSelector ( data ) ;
108
56
109
- return items . map ( ( item ) => < ListItem key = { item . id } item = { item } /> )
110
- } ;
57
+ return items . map ( item => ( < Row key = { item . id } item = { item } /> ) ) ;
58
+ }
111
59
112
- const Button = ( { id, title , cb } ) => (
60
+ const Button = ( { id, cb , title } ) => (
113
61
< div className = "col-sm-6 smallpad" >
114
62
< button type = "button" className = "btn btn-primary btn-block" id = { id } onClick = { cb } > { title } </ button >
115
63
</ div >
@@ -119,26 +67,49 @@ const Main = () => (
119
67
< div className = "container" >
120
68
< div className = "jumbotron" >
121
69
< div className = "row" >
122
- < div className = "col-md-6" > < h1 > React Tagged State </ h1 > </ div >
70
+ < div className = "col-md-6" >
71
+ < h1 > React Tagged State keyed</ h1 >
72
+ </ div >
123
73
< div className = "col-md-6" >
124
74
< div className = "row" >
125
- < Button id = "run" title = "Create 1,000 rows" cb = { run } />
126
- < Button id = "runlots" title = "Create 10,000 rows" cb = { runLots } />
127
- < Button id = "add" title = "Append 1,000 rows" cb = { add } />
128
- < Button id = "update" title = "Update every 10th row" cb = { update } />
129
- < Button id = "clear" title = "Clear" cb = { clear } />
130
- < Button id = "swaprows" title = "Swap Rows" cb = { swap } />
75
+ < Button id = "run" title = "Create 1,000 rows" cb = { ( ) => {
76
+ data ( buildData ( 1000 ) ) ;
77
+ selected ( 0 ) ;
78
+ } } />
79
+ < Button id = "runlots" title = "Create 10,000 rows" cb = { ( ) => {
80
+ data ( buildData ( 10000 ) ) ;
81
+ selected ( 0 ) ;
82
+ } } />
83
+ < Button id = "add" title = "Append 1,000 rows"
84
+ cb = { ( ) => data ( ( curr ) => curr . concat ( buildData ( 1000 ) ) ) } />
85
+ < Button id = "update" title = "Update every 10th row" cb = { ( ) => data ( ( curr ) => {
86
+ const newData = curr . slice ( 0 ) ;
87
+
88
+ for ( let i = 0 ; i < newData . length ; i += 10 ) {
89
+ const r = newData [ i ] ;
90
+
91
+ newData [ i ] = { id : r . id , label : r . label + " !!!" } ;
92
+ }
93
+
94
+ return newData ;
95
+ } ) } />
96
+ < Button id = "clear" title = "Clear" cb = { ( ) => {
97
+ data ( [ ] ) ;
98
+ selected ( 0 ) ;
99
+ } } />
100
+ < Button id = "swaprows" title = "Swap Rows"
101
+ cb = { ( ) => data ( ( curr ) => curr . length > 998 ? [ curr [ 0 ] , curr [ 998 ] , ...curr . slice ( 2 , 998 ) , curr [ 1 ] , curr [ 999 ] ] : curr ) } />
131
102
</ div >
132
103
</ div >
133
104
</ div >
134
105
</ div >
135
106
< table className = "table table-hover table-striped test-data" >
136
107
< tbody >
137
- < List />
108
+ < Rows />
138
109
</ tbody >
139
110
</ table >
140
111
< span className = "preloadicon glyphicon glyphicon-remove" aria-hidden = "true" />
141
112
</ div >
142
- ) ;
113
+ )
143
114
144
115
createRoot ( document . getElementById ( "main" ) ) . render ( < Main /> ) ;
0 commit comments