@@ -18,13 +18,30 @@ export type Props = {
1818 children ?: ?( state : State ) => ?React . Node ,
1919}
2020
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+
2137export const ScriptsRegistryContext : React . Context < ?ScriptsRegistry > = React . createContext (
2238 null
2339)
2440
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 )
2644 state = getState ( this . props )
27- promise : ?Promise < void >
2845
2946 static propTypes = {
3047 src : PropTypes . string . isRequired ,
@@ -33,91 +50,56 @@ export default class ScriptLoader extends React.PureComponent<Props, State> {
3350 children : PropTypes . func ,
3451 }
3552
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 )
6156 }
6257
63- componentDidMount ( ) {
64- this . load ( )
58+ componentWillUnmount ( ) {
59+ this . mounted = false
6560 }
6661
6762 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+ }
6969 }
7070
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+ )
7386 }
7487
7588 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
10695 }
10796}
10897
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