@@ -18,13 +18,30 @@ export type Props = {
18
18
children ?: ?( state : State ) => ?React . Node ,
19
19
}
20
20
21
+ export type InnerProps = Props & {
22
+ scriptsRegistry ?: ?ScriptsRegistry ,
23
+ }
24
+
25
+ export class ScriptsRegistry {
26
+ scripts : Array < {
27
+ src : string ,
28
+ } > = [ ]
29
+ results: { [ src : string ] : { error : ?Error } } = { }
30
+ promises: { [ src : string ] : Promise < any > } = { }
31
+
32
+ scriptTags ( ) : React . Node {
33
+ return this . scripts . map ( props => < script key = { props . src } { ...props } /> )
34
+ }
35
+ }
36
+
21
37
export const ScriptsRegistryContext : React . Context < ?ScriptsRegistry > = React . createContext (
22
38
null
23
39
)
24
40
25
- export default class ScriptLoader extends React . PureComponent < Props , State > {
41
+ class ScriptLoader extends React . PureComponent < InnerProps , State > {
42
+ mounted : boolean = false
43
+ promise : Promise < void > = loadScript ( this . props )
26
44
state = getState ( this . props )
27
- promise : ?Promise < void >
28
45
29
46
static propTypes = {
30
47
src : PropTypes . string . isRequired ,
@@ -33,91 +50,56 @@ export default class ScriptLoader extends React.PureComponent<Props, State> {
33
50
children : PropTypes . func ,
34
51
}
35
52
36
- load ( ) {
37
- const { props } = this
38
- const {
39
- onLoad ,
40
- onError ,
41
- children , // eslint-disable-line no-unused-vars
42
- ...loadProps
43
- } = props
44
- const promise = loadScript ( loadProps )
45
- if ( this . promise !== promise ) {
46
- this . promise = promise
47
- this . setState ( getState ( props ) )
48
- promise . then (
49
- ( ) => {
50
- if ( this . promise !== promise ) return
51
- if ( onLoad ) onLoad ( )
52
- this . setState ( getState ( props ) )
53
- } ,
54
- ( error : Error ) => {
55
- if ( this . promise !== promise ) return
56
- if ( onError ) onError ( error )
57
- this . setState ( getState ( props ) )
58
- }
59
- )
60
- }
53
+ componentDidMount ( ) {
54
+ this . mounted = true
55
+ this . listenTo ( this . promise )
61
56
}
62
57
63
- componentDidMount ( ) {
64
- this . load ( )
58
+ componentWillUnmount ( ) {
59
+ this . mounted = false
65
60
}
66
61
67
62
componentDidUpdate ( ) {
68
- this . load ( )
63
+ const promise = loadScript ( this . props )
64
+ if ( this . promise !== promise ) {
65
+ this . setState ( getState ( this . props ) )
66
+ this . promise = promise
67
+ this . listenTo ( promise )
68
+ }
69
69
}
70
70
71
- componentWillUnmount ( ) {
72
- this . promise = null
71
+ listenTo ( promise : Promise < any > ) {
72
+ const { props } = this
73
+ const { onLoad , onError } = props
74
+ promise . then (
75
+ ( ) => {
76
+ if ( ! this . mounted || this . promise !== promise ) return
77
+ if ( onLoad ) onLoad ( )
78
+ this . setState ( getState ( props ) )
79
+ } ,
80
+ ( error : Error ) => {
81
+ if ( ! this . mounted || this . promise !== promise ) return
82
+ if ( onError ) onError ( error )
83
+ this . setState ( getState ( props ) )
84
+ }
85
+ )
73
86
}
74
87
75
88
render ( ) : React . Node {
76
- const {
77
- children,
78
- /* eslint-disable no-unused-vars */
79
- onLoad,
80
- onError,
81
- /* eslint-enable no-unsued-vars */
82
- ...props
83
- } = this . props
84
- return (
85
- < ScriptsRegistryContext . Consumer >
86
- { ( context : ?ScriptsRegistry ) => {
87
- if ( context ) {
88
- context . scripts . push ( props )
89
- if ( ! children ) return < React . Fragment />
90
- const result = children ( {
91
- loading : true ,
92
- loaded : false ,
93
- error : null ,
94
- promise : new Promise ( ( ) => { } ) ,
95
- } )
96
- return result == null ? null : result
97
- }
98
- if ( children ) {
99
- const result = children ( { ...this . state } )
100
- return result == null ? null : result
101
- }
102
- return null
103
- } }
104
- </ ScriptsRegistryContext . Consumer >
105
- )
89
+ const { children } = this . props
90
+ if ( children ) {
91
+ const result = children ( { ...this . state } )
92
+ return result == null ? null : result
93
+ }
94
+ return null
106
95
}
107
96
}
108
97
109
- export class ScriptsRegistry {
110
- scripts : Array < {
111
- src : string ,
112
- } > = [ ]
113
-
114
- scriptTags ( ) : React . Node {
115
- return (
116
- < React . Fragment >
117
- { this . scripts . map ( ( props , index ) => (
118
- < script key = { index } { ...props } />
119
- ) ) }
120
- </ React . Fragment >
121
- )
122
- }
123
- }
98
+ const ConnectedScriptsLoader = ( props : Props ) = > (
99
+ < ScriptsRegistryContext . Consumer >
100
+ { scriptsRegistry => (
101
+ < ScriptLoader { ...props } scriptsRegistry = { scriptsRegistry } />
102
+ ) }
103
+ </ ScriptsRegistryContext . Consumer >
104
+ )
105
+ export default ConnectedScriptsLoader
0 commit comments