1
+ import { createContext , useContext , useEffect , useState } from 'react' ;
2
+ import { pathOr , toPairs } from 'ramda' ;
3
+ import loadLibrary from './loadLibrary' ;
4
+ import { batch , useDispatch , useSelector } from 'react-redux' ;
5
+ import { LibrariesState } from './libraryTypes' ;
1
6
import {
2
- createContext ,
3
- useContext ,
4
- useReducer ,
5
- useEffect ,
6
- useState
7
- } from 'react' ;
8
- import { assocPath , pathOr , pipe , toPairs } from 'ramda' ;
9
-
10
- type LibraryResource = {
11
- type : '_js_dist' | '_css_dist' ;
12
- url : string ;
13
- async ?: string ;
14
- namespace : string ;
15
- relative_package_path ?: string ;
16
- } ;
17
-
18
- type LibrariesState = {
19
- [ libname : string ] : {
20
- toLoad : boolean ;
21
- loading : boolean ;
22
- loaded : boolean ;
23
- dist ?: LibraryResource [ ] ;
24
- } ;
25
- } ;
26
-
27
- enum LibrariesActions {
28
- LOAD ,
29
- LOADED ,
30
- TO_LOAD
31
- }
32
-
33
- type LoadingPayload = {
34
- libraries : string [ ] ;
35
- } ;
36
-
37
- type LoadedPayload = {
38
- libraries : string [ ] ;
39
- } ;
40
-
41
- type ToLoadPayload = {
42
- library : string ;
43
- } ;
44
-
45
- type LibrariesAction = {
46
- type : LibrariesActions ;
47
- payload : LoadingPayload | LoadedPayload | ToLoadPayload ;
48
- } ;
7
+ setLibraryLoaded ,
8
+ setLibraryLoading ,
9
+ setLibraryToLoad
10
+ } from '../actions/libraries' ;
11
+ import fetchDist from './fetchDist' ;
49
12
50
13
export type LibrariesContextType = {
51
14
state : LibrariesState ;
52
- setLoading : ( payload : LoadingPayload ) => void ;
53
- setLoaded : ( payload : LoadedPayload ) => void ;
54
- setToLoad : ( payload : ToLoadPayload ) => void ;
55
15
isLoading : ( libraryName : string ) => boolean ;
56
16
isLoaded : ( libraryName : string ) => boolean ;
57
17
fetchLibraries : ( ) => void ;
58
18
getLibrariesToLoad : ( ) => string [ ] ;
59
19
addToLoad : ( libName : string ) => void ;
60
20
} ;
61
21
62
- function handleLoad ( library : string , state : LibrariesState ) {
63
- return pipe (
64
- assocPath ( [ library , 'loading' ] , true ) ,
65
- assocPath ( [ library , 'toLoad' ] , false )
66
- ) ( state ) as LibrariesState ;
67
- }
68
-
69
- function handleLoaded ( library : string , state : LibrariesState ) {
70
- return pipe (
71
- assocPath ( [ library , 'loaded' ] , true ) ,
72
- assocPath ( [ library , 'loading' ] , false )
73
- ) ( state ) as LibrariesState ;
74
- }
75
-
76
- export function librariesReducer (
77
- state : LibrariesState ,
78
- action : LibrariesAction
79
- ) : LibrariesState {
80
- switch ( action . type ) {
81
- case LibrariesActions . LOAD :
82
- return ( action . payload as LoadingPayload ) . libraries . reduce (
83
- ( acc , lib ) => handleLoad ( lib , acc ) ,
84
- state
85
- ) ;
86
- case LibrariesActions . LOADED :
87
- return ( action . payload as LoadedPayload ) . libraries . reduce (
88
- ( acc , lib ) => handleLoaded ( lib , acc ) ,
89
- state
90
- ) ;
91
- case LibrariesActions . TO_LOAD :
92
- return pipe (
93
- assocPath (
94
- [ ( action . payload as ToLoadPayload ) . library , 'toLoad' ] ,
95
- true
96
- )
97
- ) ( state ) as LibrariesState ;
98
- default :
99
- return state ;
100
- }
22
+ function librarySelector ( s : any ) {
23
+ return s . libraries as LibrariesState ;
101
24
}
102
25
103
26
export function createLibrariesContext (
@@ -106,26 +29,9 @@ export function createLibrariesContext(
106
29
onReady : ( ) => void ,
107
30
ready : boolean
108
31
) : LibrariesContextType {
109
- const [ state , dispatch ] = useReducer ( librariesReducer , { } , ( ) => {
110
- const libState : LibrariesState = { } ;
111
- initialLibraries . forEach ( lib => {
112
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
113
- // @ts -ignore
114
- if ( window [ lib ] ) {
115
- libState [ lib ] = { toLoad : false , loaded : true , loading : false } ;
116
- } else {
117
- libState [ lib ] = { toLoad : true , loaded : false , loading : false } ;
118
- }
119
- } ) ;
120
- return libState ;
121
- } ) ;
32
+ const dispatch = useDispatch ( ) ;
33
+ const state = useSelector ( librarySelector ) ;
122
34
const [ callback , setCallback ] = useState < number > ( - 1 ) ;
123
- const createAction = ( type : LibrariesActions ) => ( payload : any ) =>
124
- dispatch ( { type, payload} ) ;
125
-
126
- const setLoading = createAction ( LibrariesActions . LOAD ) ;
127
- const setLoaded = createAction ( LibrariesActions . LOADED ) ;
128
- const setToLoad = createAction ( LibrariesActions . TO_LOAD ) ;
129
35
130
36
const isLoaded = ( libraryName : string ) =>
131
37
pathOr ( false , [ libraryName , 'loaded' ] , state ) ;
@@ -139,9 +45,9 @@ export function createLibrariesContext(
139
45
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
140
46
// @ts -ignore
141
47
if ( window [ libraryName ] ) {
142
- setLoaded ( { libraries : [ libraryName ] } ) ;
48
+ dispatch ( setLibraryLoaded ( { libraries : [ libraryName ] } ) ) ;
143
49
} else {
144
- setToLoad ( { library : libraryName } ) ;
50
+ dispatch ( setLibraryToLoad ( { library : libraryName } ) ) ;
145
51
}
146
52
}
147
53
// if lib is already in don't do anything.
@@ -161,57 +67,42 @@ export function createLibrariesContext(
161
67
return ;
162
68
}
163
69
164
- setLoading ( { libraries} ) ;
70
+ dispatch ( setLibraryLoading ( { libraries} ) ) ;
165
71
166
- fetch ( `${ pathnamePrefix } _dash-dist` , {
167
- body : JSON . stringify ( libraries ) ,
168
- headers : { 'Content-Type' : 'application/json' } ,
169
- method : 'POST'
170
- } )
171
- . then ( response => response . json ( ) )
72
+ fetchDist ( pathnamePrefix , libraries )
172
73
. then ( data => {
173
- const head = document . querySelector ( 'head' ) ;
174
- const loadPromises : Promise < void > [ ] = [ ] ;
175
- data . forEach ( ( resource : LibraryResource ) => {
176
- if ( resource . type === '_js_dist' ) {
177
- const element = document . createElement ( 'script' ) ;
178
- element . src = resource . url ;
179
- element . async = true ;
180
- loadPromises . push (
181
- new Promise ( ( resolve , reject ) => {
182
- element . onload = ( ) => {
183
- resolve ( ) ;
184
- } ;
185
- element . onerror = error => reject ( error ) ;
186
- } )
187
- ) ;
188
- head ?. appendChild ( element ) ;
189
- } else if ( resource . type === '_css_dist' ) {
190
- const element = document . createElement ( 'link' ) ;
191
- element . href = resource . url ;
192
- element . rel = 'stylesheet' ;
193
- loadPromises . push (
194
- new Promise ( ( resolve , reject ) => {
195
- element . onload = ( ) => {
196
- resolve ( ) ;
197
- } ;
198
- element . onerror = error => reject ( error ) ;
199
- } )
200
- ) ;
201
- head ?. appendChild ( element ) ;
202
- }
203
- } ) ;
204
- return Promise . all ( loadPromises ) ;
74
+ return Promise . all ( data . map ( loadLibrary ) ) ;
205
75
} )
206
76
. then ( ( ) => {
207
- setLoaded ( { libraries} ) ;
77
+ dispatch ( setLibraryLoaded ( { libraries} ) ) ;
208
78
setCallback ( - 1 ) ;
209
79
onReady ( ) ;
210
80
} ) ;
211
81
} ;
212
82
83
+ useEffect ( ( ) => {
84
+ batch ( ( ) => {
85
+ const loaded : string [ ] = [ ] ;
86
+ initialLibraries . forEach ( lib => {
87
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
88
+ // @ts -ignore
89
+ if ( window [ lib ] ) {
90
+ loaded . push ( lib ) ;
91
+ } else {
92
+ dispatch ( setLibraryToLoad ( { library : lib } ) ) ;
93
+ }
94
+ } ) ;
95
+ if ( loaded . length ) {
96
+ dispatch ( setLibraryLoaded ( { libraries : loaded } ) ) ;
97
+ }
98
+ } ) ;
99
+ } , [ initialLibraries ] ) ;
100
+
213
101
// Load libraries on a throttle to have time to gather all the components in one go.
214
102
useEffect ( ( ) => {
103
+ if ( ready ) {
104
+ return ;
105
+ }
215
106
const libraries = getLibrariesToLoad ( ) ;
216
107
if ( ! libraries . length ) {
217
108
if ( ! ready && initialLibraries . length === 0 ) {
@@ -224,13 +115,10 @@ export function createLibrariesContext(
224
115
}
225
116
const timeout = window . setTimeout ( fetchLibraries , 0 ) ;
226
117
setCallback ( timeout ) ;
227
- } , [ state ] ) ;
118
+ } , [ state , ready ] ) ;
228
119
229
120
return {
230
121
state,
231
- setLoading,
232
- setLoaded,
233
- setToLoad,
234
122
isLoaded,
235
123
isLoading,
236
124
fetchLibraries,
0 commit comments