1
1
import { loopAsync } from './AsyncUtils'
2
2
3
- function createTransitionHook ( hook , route , asyncArity ) {
4
- return function ( ...args ) {
3
+ class PendingHooks {
4
+ hooks = [ ]
5
+ add = hook => this . hooks . push ( hook )
6
+ remove = hook => this . hooks = this . hooks . filter ( h => h !== hook )
7
+ has = hook => this . hooks . indexOf ( hook ) !== - 1
8
+ clear = ( ) => this . hooks = [ ]
9
+ }
10
+
11
+ const enterHooks = new PendingHooks ( )
12
+ const changeHooks = new PendingHooks ( )
13
+
14
+ function createTransitionHook ( hook , route , asyncArity , pendingHooks ) {
15
+ const transitionHook = ( ...args ) => {
5
16
hook . apply ( route , args )
6
17
7
18
if ( hook . length < asyncArity ) {
8
19
let callback = args [ args . length - 1 ]
20
+ // Add synchronous hook to pendingHooks (gets removed instantly later)
21
+ pendingHooks . add ( transitionHook )
9
22
// Assume hook executes synchronously and
10
23
// automatically call the callback.
11
24
callback ( )
12
25
}
13
26
}
27
+
28
+ if ( hook . length >= asyncArity ) {
29
+ pendingHooks . add ( transitionHook )
30
+ }
31
+
32
+ return transitionHook
14
33
}
15
34
16
35
function getEnterHooks ( routes ) {
17
36
return routes . reduce ( function ( hooks , route ) {
18
37
if ( route . onEnter )
19
- hooks . push ( createTransitionHook ( route . onEnter , route , 3 ) )
20
-
38
+ hooks . push ( createTransitionHook ( route . onEnter , route , 3 , enterHooks ) )
21
39
return hooks
22
40
} , [ ] )
23
41
}
24
42
25
43
function getChangeHooks ( routes ) {
26
44
return routes . reduce ( function ( hooks , route ) {
27
45
if ( route . onChange )
28
- hooks . push ( createTransitionHook ( route . onChange , route , 4 ) )
46
+ hooks . push ( createTransitionHook ( route . onChange , route , 4 , changeHooks ) )
29
47
return hooks
30
48
} , [ ] )
31
49
}
@@ -63,9 +81,16 @@ function runTransitionHooks(length, iter, callback) {
63
81
* which could lead to a non-responsive UI if the hook is slow.
64
82
*/
65
83
export function runEnterHooks ( routes , nextState , callback ) {
84
+ enterHooks . clear ( )
66
85
const hooks = getEnterHooks ( routes )
67
86
return runTransitionHooks ( hooks . length , ( index , replace , next ) => {
68
- hooks [ index ] ( nextState , replace , next )
87
+ const wrappedNext = ( ) => {
88
+ if ( enterHooks . has ( hooks [ index ] ) ) {
89
+ next ( )
90
+ enterHooks . remove ( hooks [ index ] )
91
+ }
92
+ }
93
+ hooks [ index ] ( nextState , replace , wrappedNext )
69
94
} , callback )
70
95
}
71
96
@@ -80,9 +105,16 @@ export function runEnterHooks(routes, nextState, callback) {
80
105
* which could lead to a non-responsive UI if the hook is slow.
81
106
*/
82
107
export function runChangeHooks ( routes , state , nextState , callback ) {
108
+ changeHooks . clear ( )
83
109
const hooks = getChangeHooks ( routes )
84
110
return runTransitionHooks ( hooks . length , ( index , replace , next ) => {
85
- hooks [ index ] ( state , nextState , replace , next )
111
+ const wrappedNext = ( ) => {
112
+ if ( changeHooks . has ( hooks [ index ] ) ) {
113
+ next ( )
114
+ changeHooks . remove ( hooks [ index ] )
115
+ }
116
+ }
117
+ hooks [ index ] ( state , nextState , replace , wrappedNext )
86
118
} , callback )
87
119
}
88
120
0 commit comments