1
1
import { Component , ReactNode } from 'react'
2
+
2
3
import { Value } from '../primitive'
3
4
import RenderChild from '../RenderChild'
4
5
@@ -8,6 +9,7 @@ export interface ImageControlProps {
8
9
src : string
9
10
srcSet ?: string
10
11
stub ?: string | ReactNode
12
+ cachedDelay ?: number
11
13
viewedDelay ?: number
12
14
onLoad ?: ( ) => void
13
15
children : RenderChild < {
@@ -19,94 +21,111 @@ export interface ImageControlProps {
19
21
} >
20
22
}
21
23
24
+ enum Step {
25
+ NONE ,
26
+ CHECK_CACHE ,
27
+ NO_CACHE ,
28
+ LOAD ,
29
+ DONE ,
30
+ }
31
+
22
32
export interface ImageControlState {
23
- viewed : boolean
24
- loaded : boolean
33
+ step : Step
25
34
}
26
35
27
36
export class ImageControl extends Component < ImageControlProps , ImageControlState > {
28
37
29
38
public static defaultProps = {
39
+ cachedDelay : 50 ,
30
40
viewedDelay : 1000 ,
31
41
}
32
42
33
43
public state : ImageControlState = {
34
- viewed : false ,
35
- loaded : false ,
44
+ step : Step . NONE ,
36
45
}
37
46
38
- private viewedTimer : number | undefined
39
-
40
47
public componentWillUnmount : ( ) => void = ( ) => {
41
48
clearTimeout ( this . viewedTimer )
49
+ clearTimeout ( this . cachedTimer )
42
50
}
43
51
52
+ private viewedTimer : number | undefined
53
+
54
+ private cachedTimer : number | undefined
55
+
44
56
private onChange : ( inView : boolean ) => void = ( inView ) => {
45
57
clearTimeout ( this . viewedTimer )
46
58
if ( ! inView ) {
47
59
return
48
60
}
49
- if ( this . isCached ) {
61
+ if ( this . state . step === Step . NONE ) {
50
62
this . setState ( {
51
- viewed : true ,
63
+ step : Step . CHECK_CACHE ,
52
64
} )
53
- return
65
+ const image = document . createElement ( 'img' )
66
+ image . src = this . props . src
67
+ image . srcset = this . props . srcSet || ''
68
+ image . onload = ( ) => {
69
+ clearTimeout ( this . viewedTimer )
70
+ clearTimeout ( this . cachedTimer )
71
+ this . setState ( {
72
+ step : Step . LOAD ,
73
+ } )
74
+ }
75
+ this . cachedTimer = setTimeout ( ( ) => {
76
+ image . onload = null
77
+ image . src = ''
78
+ image . srcset = ''
79
+ this . setState ( {
80
+ step : Step . NO_CACHE ,
81
+ } )
82
+ } , this . props . cachedDelay )
54
83
}
55
84
this . viewedTimer = setTimeout ( ( ) => {
56
85
this . setState ( {
57
- viewed : true ,
86
+ step : Step . LOAD ,
58
87
} )
59
88
} , this . props . viewedDelay )
60
89
}
61
90
62
91
private onLoad : ( ) => void = ( ) => {
63
- if ( ! this . state . viewed ) {
92
+ if ( this . state . step !== Step . LOAD ) {
64
93
return
65
94
}
66
95
if ( this . props . onLoad ) {
67
96
this . props . onLoad ( )
68
97
}
69
98
this . setState ( {
70
- loaded : true ,
99
+ step : Step . DONE ,
71
100
} )
72
101
}
73
102
74
103
private get src ( ) : string | undefined {
75
104
const { stub, src} = this . props
76
- if ( this . state . viewed ) {
105
+ if ( this . state . step === Step . LOAD || this . state . step === Step . DONE ) {
77
106
return src
78
107
}
108
+ if ( this . state . step === Step . NONE || this . state . step === Step . CHECK_CACHE ) {
109
+ return undefined
110
+ }
79
111
if ( typeof stub === 'string' ) {
80
112
return stub
81
113
}
82
114
return undefined
83
115
}
84
116
85
117
private get srcSet ( ) : string | undefined {
86
- if ( ! this . state . viewed ) {
87
- return undefined
88
- }
89
- return this . props . srcSet
90
- }
91
-
92
- private get isCached ( ) : boolean {
93
- try {
94
- const image = document . createElement ( 'img' )
95
- image . src = this . props . src
96
- const complete = image . complete
97
- image . src = ''
98
- return complete
99
- }
100
- catch ( e ) {
101
- return false
118
+ if ( this . state . step === Step . LOAD || this . state . step === Step . DONE ) {
119
+ return this . props . srcSet
102
120
}
121
+ return undefined
103
122
}
104
123
105
124
public render ( ) {
106
125
return this . props . children ( {
107
126
src : this . src ,
108
127
srcSet : this . srcSet ,
109
- loaded : this . state . loaded ,
128
+ loaded : this . state . step === Step . DONE ,
110
129
onChange : this . onChange ,
111
130
onLoad : this . onLoad ,
112
131
} )
0 commit comments