1- import { hookstate , State , useHookstate } from '@hookstate/core' ;
2- import { useEffect } from 'react' ;
3- import './App.css' ;
1+ import React , { useEffect } from 'react' ;
2+ import { useHookstate , State } from '@hookstate/core' ;
43
5- const createId = ( ) => {
6- return Math . floor ( Math . random ( ) * 0xffffff ) . toString ( 16 ) ;
7- } ;
8-
9- interface IItem {
10- id : string ;
11- kind : string ;
12- type : string ;
4+ const TableCell = ( props : { cell : State < number > } ) => {
5+ const scopedState = useHookstate ( props . cell ) ;
6+ return < > { scopedState . value . toString ( 16 ) } </ > ;
137}
148
15- interface IAppState {
16- items : Record < string , IItem > ;
9+ type StatsExtension = {
10+ stats : {
11+ totalSum : number ;
12+ totalCalls : number ;
13+ startTime : number ;
14+ } ;
1715}
1816
19- const appState = hookstate < IAppState > ( {
20- items : {
21- initial : {
22- id : 'initial' ,
23- kind : 'UNKNOWN' ,
24- type : 'test' ,
25- } ,
26- } ,
27- } ) ;
28-
29- function App ( ) {
30- const state = useHookstate ( appState ) ;
17+ const MatrixView = ( props : {
18+ totalRows : number ,
19+ totalColumns : number ,
20+ interval : number ,
21+ callsPerInterval : number
22+ } ) => {
23+ const matrix = useHookstate (
24+ ( ) => Array . from ( Array ( props . totalRows ) . keys ( ) )
25+ . map ( i => Array . from ( Array ( props . totalColumns ) . keys ( ) ) . map ( j => 0 ) ) ,
26+ ( ) => {
27+ const stats = {
28+ totalSum : 0 ,
29+ totalCalls : 0 ,
30+ startTime : ( new Date ( ) ) . getTime ( )
31+ } ;
3132
33+ let previous = 0 ;
34+ return {
35+ onCreate : ( ) => ( {
36+ stats : ( ) => stats
37+ } ) ,
38+ onPreset : ( s ) => {
39+ if ( s . path . length === 2 ) {
40+ previous = s . get ( { stealth : true } ) ;
41+ }
42+ } ,
43+ onSet : ( s ) => {
44+ if ( s . path . length === 2 ) {
45+ // new value can be only number in this example
46+ // and path can contain only 2 elements: row and column indexes
47+ stats . totalSum += s . value - previous ;
48+ }
49+ stats . totalCalls += 1 ;
50+ }
51+ }
52+ }
53+ ) ;
54+ // schedule interval updates
3255 useEffect ( ( ) => {
33- console . log ( 'Keys changed.' ) ;
34- } , [ state . items . keys ] ) ;
56+ const t = setInterval ( ( ) => {
57+ function randomInt ( min : number , max : number ) {
58+ min = Math . ceil ( min ) ;
59+ max = Math . floor ( max ) ;
60+ return Math . floor ( Math . random ( ) * ( max - min ) ) + min ;
61+ }
62+ for ( let i = 0 ; i < props . callsPerInterval ; i += 1 ) {
63+ matrix
64+ [ randomInt ( 0 , props . totalRows ) ]
65+ [ randomInt ( 0 , props . totalColumns ) ]
66+ . set ( p => p + randomInt ( 0 , 5 ) )
67+ }
68+ } , props . interval )
69+ return ( ) => clearInterval ( t ) ;
70+ } , [ props . interval , props . callsPerInterval , props . totalRows , props . totalColumns ] )
71+
72+ return < div style = { { overflow : 'scroll' } } >
73+ < PerformanceMeter matrix = { matrix } />
74+ < table
75+ style = { {
76+ border : 'solid' ,
77+ borderWidth : 1 ,
78+ borderColor : 'grey' ,
79+ color : '#00FF00' ,
80+ backgroundColor : 'black'
81+ } }
82+ >
83+ < tbody >
84+ { matrix . map ( ( rowState , rowIndex : number ) =>
85+ < tr key = { rowIndex } >
86+ { rowState . map ( ( cellState , columnIndex ) =>
87+ < td key = { columnIndex } >
88+ < TableCell cell = { cellState } />
89+ </ td >
90+ ) }
91+ </ tr >
92+ ) }
93+ </ tbody >
94+ </ table >
95+ </ div >
96+ }
3597
36- return (
98+ export const ExampleComponent = ( ) => {
99+ const settings = useHookstate ( {
100+ rows : 50 ,
101+ columns : 50 ,
102+ rate : 50 ,
103+ timer : 10
104+ } )
105+ return < >
37106 < div >
38- < div >
39- < button
40- onClick = { ( ) => {
41- const id = createId ( ) ;
42- // state.items.merge({ [id]: { id, kind: 'UNKNOWN', type: 'test' } });
43- state . items [ id ] . set ( { id, kind : 'UNKNOWN' , type : 'test' } ) ;
44- } }
45- >
46- Add
47- </ button >
48- </ div >
49- < div >
50- { state . items . keys . map ( ( itemId ) => (
51- < Item key = { itemId } state = { state . items [ itemId ] } />
52- ) ) }
53- </ div >
107+ < p > < span > Total rows: { settings . rows . value } </ span >
108+ < button onClick = { ( ) =>
109+ settings . rows . set ( p => ( p - 10 ) || 10 ) } > -10</ button >
110+ < button onClick = { ( ) =>
111+ settings . rows . set ( p => p + 10 ) } > +10</ button > </ p >
112+ < p > < span > Total columns: { settings . columns . value } </ span >
113+ < button onClick = { ( ) =>
114+ settings . columns . set ( p => ( p - 10 ) || 10 ) } > -10</ button >
115+ < button onClick = { ( ) =>
116+ settings . columns . set ( p => p + 10 ) } > +10</ button > </ p >
117+ < p > Total cells: { settings . columns . value * settings . rows . value } </ p >
118+ < p > < span > Cells to update per timer interval: { settings . rate . value } </ span >
119+ < button onClick = { ( ) =>
120+ settings . rate . set ( p => ( p - 1 ) || 1 ) } > -1</ button >
121+ < button onClick = { ( ) =>
122+ settings . rate . set ( p => p + 1 ) } > +1</ button >
123+ < button onClick = { ( ) =>
124+ settings . rate . set ( p => p > 10 ? ( p - 10 ) : 1 ) } > -10</ button >
125+ < button onClick = { ( ) =>
126+ settings . rate . set ( p => p + 10 ) } > +10</ button >
127+ </ p >
128+ < p > < span > Timer interval in ms: { settings . timer . value } </ span >
129+ < button onClick = { ( ) =>
130+ settings . timer . set ( p => p > 1 ? ( p - 1 ) : 1 ) } > -1</ button >
131+ < button onClick = { ( ) =>
132+ settings . timer . set ( p => p + 1 ) } > +1</ button >
133+ < button onClick = { ( ) =>
134+ settings . timer . set ( p => p > 10 ? ( p - 10 ) : 1 ) } > -10</ button >
135+ < button onClick = { ( ) =>
136+ settings . timer . set ( p => p + 10 ) } > +10</ button >
137+ </ p >
54138 </ div >
55- ) ;
139+ < MatrixView
140+ key = { Math . random ( ) }
141+ totalRows = { settings . rows . value }
142+ totalColumns = { settings . columns . value }
143+ interval = { settings . timer . value }
144+ callsPerInterval = { settings . rate . value }
145+ />
146+ </ > ;
56147}
57148
58- function Item ( props : { state : State < IItem > } ) {
59- const state = useHookstate ( props . state ) ;
149+ function PerformanceMeter ( props : { matrix : State < number [ ] [ ] , StatsExtension > } ) {
150+ let stats = props . matrix . stats ;
151+ const elapsedMs = ( ) => ( new Date ( ) ) . getTime ( ) - stats . startTime ;
152+ const elapsed = ( ) => Math . floor ( elapsedMs ( ) / 1000 ) ;
153+ const rate = Math . floor ( stats . totalCalls / elapsedMs ( ) * 1000 ) ;
60154
61- return (
62- < div
63- style = { { padding : 10 , backgroundColor : '#' + Math . floor ( Math . random ( ) * 0xffffff ) . toString ( 16 ) } }
64- onClick = { ( ) => {
65- state . type . set ( Math . random ( ) . toString ( 16 ) ) ;
66- } }
67- >
68- { JSON . stringify ( state . value ) }
69- </ div >
70- ) ;
155+ // this makes rerendering this component every 200ms
156+ let forceRerender = useHookstate ( 1 ) ;
157+ useEffect ( ( ) => {
158+ const interval = setInterval ( ( ) => {
159+ forceRerender . set ( p => p + 1 )
160+ } , 200 )
161+ return ( ) => clearInterval ( interval )
162+ } , [ ] )
163+
164+ return < >
165+ < p > < span > Elapsed: { elapsed ( ) } s</ span > </ p >
166+ < p > < span > Total cells sum: { stats . totalSum } </ span > </ p >
167+ < p > < span > Total matrix state updates: { stats . totalCalls } </ span > </ p >
168+ < p > < span > Average update rate: { rate } cells/s</ span > </ p >
169+ </ > ;
71170}
72171
73- export default App ;
172+ export const App = ExampleComponent
0 commit comments