1- import React , { useContext , useMemo , useReducer } from "react" ;
1+ import React , { useContext , useMemo , useRef , useEffect , useState } from "react" ;
22import { Prism as SyntaxHighlighter } from "react-syntax-highlighter" ;
33import highlightStyle from "react-syntax-highlighter/dist/esm/styles/prism/tomorrow" ;
44import Explanation from "../Explanation" ;
55import Preface from "../Preface" ;
66import cloneDeep from "lodash.clonedeep" ;
77
8- export interface ILogger {
9- log : ( message : string , mixed ?: any ) => void ;
10- }
11-
12- interface ILogs {
13- logs : ILog [ ] ;
14- id : number ;
15- }
16-
17- interface ILog {
18- id : number ;
8+ interface Log {
199 message : string ;
10+ fireDate : number ;
11+ elapsedTime : number | null ;
2012 mixed ?: any ;
21- time : number ;
2213}
14+ type LogAction = ( message : string , mixed ?: any ) => void ;
15+ interface LogContext {
16+ action : LogAction ;
17+ logs : React . MutableRefObject < Log [ ] > ;
18+ observers : React . MutableRefObject < ( ( ) => void ) [ ] > ;
19+ }
20+ const LoggerContext = React . createContext < LogContext | null > ( null ) ;
21+ export const useLog = ( ) => {
22+ const context = useContext ( LoggerContext ) ! ;
23+ useEffect ( ( ) => {
24+ const renderDate = Date . now ( ) ;
25+ context . logs . current = context . logs . current . map ( tLog => {
26+ return ! tLog . elapsedTime ? {
27+ ...tLog ,
28+ elapsedTime : renderDate - tLog . fireDate
29+ } : tLog ;
30+ } ) ;
31+ context . observers . current . forEach ( observer => observer ( ) ) ;
32+ } ) ;
2333
24- const LoggerContext = React . createContext < ILogger | null > ( null ) ;
34+ return context . action ;
35+ } ;
36+ const useLogObserver = ( ) => {
37+ const context = useContext ( LoggerContext ) ! ;
38+ const [ _ , setTrigger ] = useState < number > ( 0 ) ;
2539
26- export const useLog = ( ) => {
27- return useContext ( LoggerContext ) ! . log ;
40+ useEffect ( ( ) => {
41+ const callback = ( ) => {
42+ setTrigger ( t => t + 1 ) ;
43+ }
44+ context . observers . current . push ( callback ) ;
45+ return ( ) => {
46+ context . observers . current = context . observers . current . filter ( observer => observer !== callback ) ;
47+ } ;
48+ } , [ context ] ) ;
49+ return context . logs . current ;
2850} ;
2951
3052const Code = ( { code } : { code ?: string | null } ) => {
@@ -51,7 +73,9 @@ const Code = ({ code }: { code?: string | null }) => {
5173 ) ;
5274} ;
5375
54- const Logs = ( { logs, clear } : { logs : ILog [ ] ; clear : ( ) => void } ) => {
76+ const Logs = ( { clear } : { clear : ( ) => void } ) => {
77+ const logs = useLogObserver ( ) ;
78+
5579 return (
5680 < div
5781 style = { {
@@ -73,12 +97,12 @@ const Logs = ({ logs, clear }: { logs: ILog[]; clear: () => void }) => {
7397 { logs
7498 . map ( ( log , i ) => (
7599 < div
76- key = { log . id }
100+ key = { i }
77101 style = { { margin : 10 , borderBottom : "1px #EEE solid" } }
78102 >
79- [< span style = { { fontWeight : "bold" } } > { log . id } </ span > ] (
103+ [< span style = { { fontWeight : "bold" } } > { i } </ span > ] (
80104 < span style = { { fontStyle : "italic" } } >
81- +{ log . time - ( logs [ i - 1 ] || log ) . time } ms
105+ +{ log . elapsedTime || "..." } ms
82106 </ span >
83107 ) { log . message }
84108 < pre > { JSON . stringify ( log . mixed , null , 2 ) } </ pre >
@@ -178,39 +202,104 @@ const ExampleBloc = ({
178202 preface,
179203 explanation
180204} : IProps ) => {
181- const [ logs , dispatch ] = useReducer (
182- ( logs : ILogs , action ) : ILogs => {
183- switch ( action . type ) {
184- case "add" :
185- return {
186- logs : [ ...logs . logs , { ...action . payload , id : logs . id } ] ,
187- id : logs . id + 1
188- } ;
189-
190- case "clear" :
191- return { logs : [ ] , id : 1 } ;
192-
193- default :
194- throw new Error ( "Not implemented: " + action . type ) ;
195- }
196- } ,
197- { logs : [ ] , id : 1 }
198- ) ;
205+ const logStorage = useRef < Log [ ] > ( [ ] ) ;
206+ const logObservers = useRef < ( ( ) => void ) [ ] > ( [ ] ) ;
199207
200208 const memoComponent = useMemo ( ( ) => {
201209 const log = ( message : string , mixed ?: any ) => {
202- dispatch ( {
203- type : "add" ,
204- payload : { message, time : Date . now ( ) , mixed : cloneDeep ( mixed ) }
205- } ) ;
210+ const newLog : Log = {
211+ message : message ,
212+ fireDate : Date . now ( ) ,
213+ elapsedTime : null ,
214+ mixed : cloneDeep ( mixed )
215+ } ;
216+ logStorage . current . push ( newLog ) ;
206217 } ;
207218
208219 return (
209- < LoggerContext . Provider value = { { log } } >
210- < Component />
220+ < LoggerContext . Provider value = { { action : log , logs : logStorage , observers : logObservers } } >
221+ < section
222+ style = { {
223+ position : "relative" ,
224+ height : "100vh" ,
225+ width : "100%" ,
226+ margin : "40px 0" ,
227+ color : "#FFFFFF" ,
228+ backgroundColor : "#282c34" ,
229+ textAlign : "left" ,
230+ fontFamily :
231+ "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif"
232+ } }
233+ >
234+ < h3
235+ id = { id }
236+ style = { {
237+ margin : 10 ,
238+ padding : 10 ,
239+ borderBottom : "1px solid #61dafb" ,
240+ display : "flex" ,
241+ justifyContent : "space-between"
242+ } }
243+ >
244+ < a style = { { color : "#61dafb" , textDecoration : "none" } } href = { `#${ id } ` } >
245+ { title }
246+ </ a >
247+ < div >
248+ { prev && (
249+ < a
250+ style = { {
251+ color : "#61dafb" ,
252+ textDecoration : "none" ,
253+ margin : "0 10px"
254+ } }
255+ href = { `#${ prev } ` }
256+ >
257+ ⇐
258+ </ a >
259+ ) }
260+ { next && (
261+ < a
262+ style = { { color : "#61dafb" , textDecoration : "none" } }
263+ href = { `#${ next } ` }
264+ >
265+ ⇒
266+ </ a >
267+ ) }
268+ </ div >
269+ </ h3 >
270+ < div
271+ style = { {
272+ display : "flex" ,
273+ flexDirection : "row" ,
274+ justifyContent : "space-around" ,
275+ position : "absolute" ,
276+ top : 50 ,
277+ bottom : 0 ,
278+ left : 0 ,
279+ right : 0
280+ } }
281+ >
282+ < Col percentage = { 40 } margin = { 30 } >
283+ < Code code = { code } />
284+ </ Col >
285+
286+ < Col percentage = { 40 } margin = { 30 } >
287+ < ComponentAndText preface = { preface } explanation = { explanation } >
288+ < Component />
289+ </ ComponentAndText >
290+ </ Col >
291+
292+ < Col percentage = { 20 } margin = { 30 } >
293+ < Logs clear = { ( ) => {
294+ logStorage . current = [ ] ;
295+ logObservers . current . forEach ( observer => observer ( ) ) ;
296+ } } />
297+ </ Col >
298+ </ div >
299+ </ section >
211300 </ LoggerContext . Provider >
212301 ) ;
213- } , [ ] ) ;
302+ } , [ logStorage , logObservers , id , title , prev , next , code , preface , explanation ] ) ;
214303
215304 if ( code ) {
216305 code = code . replace ( / \r / g, "" ) ;
@@ -219,84 +308,7 @@ const ExampleBloc = ({
219308 code = code . trim ( ) ;
220309 }
221310
222- return (
223- < section
224- style = { {
225- position : "relative" ,
226- height : "100vh" ,
227- width : "100%" ,
228- margin : "40px 0" ,
229- color : "#FFFFFF" ,
230- backgroundColor : "#282c34" ,
231- textAlign : "left" ,
232- fontFamily :
233- "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif"
234- } }
235- >
236- < h3
237- id = { id }
238- style = { {
239- margin : 10 ,
240- padding : 10 ,
241- borderBottom : "1px solid #61dafb" ,
242- display : "flex" ,
243- justifyContent : "space-between"
244- } }
245- >
246- < a style = { { color : "#61dafb" , textDecoration : "none" } } href = { `#${ id } ` } >
247- { title }
248- </ a >
249- < div >
250- { prev && (
251- < a
252- style = { {
253- color : "#61dafb" ,
254- textDecoration : "none" ,
255- margin : "0 10px"
256- } }
257- href = { `#${ prev } ` }
258- >
259- ⇐
260- </ a >
261- ) }
262- { next && (
263- < a
264- style = { { color : "#61dafb" , textDecoration : "none" } }
265- href = { `#${ next } ` }
266- >
267- ⇒
268- </ a >
269- ) }
270- </ div >
271- </ h3 >
272- < div
273- style = { {
274- display : "flex" ,
275- flexDirection : "row" ,
276- justifyContent : "space-around" ,
277- position : "absolute" ,
278- top : 50 ,
279- bottom : 0 ,
280- left : 0 ,
281- right : 0
282- } }
283- >
284- < Col percentage = { 40 } margin = { 30 } >
285- < Code code = { code } />
286- </ Col >
287-
288- < Col percentage = { 40 } margin = { 30 } >
289- < ComponentAndText preface = { preface } explanation = { explanation } >
290- { memoComponent }
291- </ ComponentAndText >
292- </ Col >
293-
294- < Col percentage = { 20 } margin = { 30 } >
295- < Logs logs = { logs . logs } clear = { ( ) => dispatch ( { type : "clear" } ) } />
296- </ Col >
297- </ div >
298- </ section >
299- ) ;
311+ return < > { memoComponent } </ > ;
300312} ;
301313
302314export default ExampleBloc ;
0 commit comments