@@ -21,49 +21,68 @@ const useAsync = (arg1, arg2) => {
21
21
options ,
22
22
init
23
23
)
24
- const dispatch = dispatcher
25
- ? action => dispatcher ( action , dispatchMiddleware ( _dispatch ) , options )
26
- : dispatchMiddleware ( _dispatch )
27
-
28
- const getMeta = meta => ( { counter : counter . current , debugLabel : options . debugLabel , ...meta } )
24
+ const dispatch = useCallback (
25
+ dispatcher
26
+ ? action => dispatcher ( action , dispatchMiddleware ( _dispatch ) , lastOptions . current )
27
+ : dispatchMiddleware ( _dispatch ) ,
28
+ [ dispatcher ]
29
+ )
29
30
30
- const setData = ( data , callback = noop ) => {
31
- if ( isMounted . current ) {
32
- dispatch ( { type : actionTypes . fulfill , payload : data , meta : getMeta ( ) } )
33
- callback ( )
34
- }
35
- return data
36
- }
31
+ const { debugLabel } = options
32
+ const getMeta = useCallback ( meta => ( { counter : counter . current , debugLabel, ...meta } ) , [
33
+ debugLabel ,
34
+ ] )
35
+
36
+ const setData = useCallback (
37
+ ( data , callback = noop ) => {
38
+ if ( isMounted . current ) {
39
+ dispatch ( { type : actionTypes . fulfill , payload : data , meta : getMeta ( ) } )
40
+ callback ( )
41
+ }
42
+ return data
43
+ } ,
44
+ [ dispatch , getMeta ]
45
+ )
37
46
38
- const setError = ( error , callback = noop ) => {
39
- if ( isMounted . current ) {
40
- dispatch ( { type : actionTypes . reject , payload : error , error : true , meta : getMeta ( ) } )
41
- callback ( )
42
- }
43
- return error
44
- }
47
+ const setError = useCallback (
48
+ ( error , callback = noop ) => {
49
+ if ( isMounted . current ) {
50
+ dispatch ( { type : actionTypes . reject , payload : error , error : true , meta : getMeta ( ) } )
51
+ callback ( )
52
+ }
53
+ return error
54
+ } ,
55
+ [ dispatch , getMeta ]
56
+ )
45
57
46
58
const { onResolve, onReject } = options
47
- const handleResolve = count => data =>
48
- count === counter . current && setData ( data , ( ) => onResolve && onResolve ( data ) )
49
- const handleReject = count => error =>
50
- count === counter . current && setError ( error , ( ) => onReject && onReject ( error ) )
51
-
52
- const start = promiseFn => {
53
- if ( "AbortController" in globalScope ) {
54
- abortController . current . abort ( )
55
- abortController . current = new globalScope . AbortController ( )
56
- }
57
- counter . current ++
58
- return new Promise ( ( resolve , reject ) => {
59
- if ( ! isMounted . current ) return
60
- const executor = ( ) => promiseFn ( ) . then ( resolve , reject )
61
- dispatch ( { type : actionTypes . start , payload : executor , meta : getMeta ( ) } )
62
- } )
63
- }
59
+ const handleResolve = useCallback (
60
+ count => data => count === counter . current && setData ( data , ( ) => onResolve && onResolve ( data ) ) ,
61
+ [ setData , onResolve ]
62
+ )
63
+ const handleReject = useCallback (
64
+ count => err => count === counter . current && setError ( err , ( ) => onReject && onReject ( err ) ) ,
65
+ [ setError , onReject ]
66
+ )
67
+
68
+ const start = useCallback (
69
+ promiseFn => {
70
+ if ( "AbortController" in globalScope ) {
71
+ abortController . current . abort ( )
72
+ abortController . current = new globalScope . AbortController ( )
73
+ }
74
+ counter . current ++
75
+ return new Promise ( ( resolve , reject ) => {
76
+ if ( ! isMounted . current ) return
77
+ const executor = ( ) => promiseFn ( ) . then ( resolve , reject )
78
+ dispatch ( { type : actionTypes . start , payload : executor , meta : getMeta ( ) } )
79
+ } )
80
+ } ,
81
+ [ dispatch , getMeta ]
82
+ )
64
83
65
84
const { promise, promiseFn, initialValue } = options
66
- const load = ( ) => {
85
+ const load = useCallback ( ( ) => {
67
86
if ( promise ) {
68
87
return start ( ( ) => promise ) . then (
69
88
handleResolve ( counter . current ) ,
@@ -77,26 +96,36 @@ const useAsync = (arg1, arg2) => {
77
96
handleReject ( counter . current )
78
97
)
79
98
}
80
- }
99
+ } , [ start , promise , promiseFn , initialValue , handleResolve , handleReject ] )
81
100
82
101
const { deferFn } = options
83
- const run = ( ...args ) => {
84
- if ( deferFn ) {
85
- lastArgs . current = args
86
- return start ( ( ) => deferFn ( args , lastOptions . current , abortController . current ) ) . then (
87
- handleResolve ( counter . current ) ,
88
- handleReject ( counter . current )
89
- )
90
- }
91
- }
102
+ const run = useCallback (
103
+ ( ...args ) => {
104
+ if ( deferFn ) {
105
+ lastArgs . current = args
106
+ return start ( ( ) => deferFn ( args , lastOptions . current , abortController . current ) ) . then (
107
+ handleResolve ( counter . current ) ,
108
+ handleReject ( counter . current )
109
+ )
110
+ }
111
+ } ,
112
+ [ start , deferFn , handleResolve , handleReject ]
113
+ )
114
+
115
+ const reload = useCallback ( ( ) => {
116
+ return lastArgs . current ? run ( ...lastArgs . current ) : load ( )
117
+ } , [ run , load ] )
92
118
93
- const cancel = ( ) => {
94
- options . onCancel && options . onCancel ( )
119
+ const { onCancel } = options
120
+ const cancel = useCallback ( ( ) => {
121
+ onCancel && onCancel ( )
95
122
counter . current ++
96
123
abortController . current . abort ( )
97
124
isMounted . current && dispatch ( { type : actionTypes . cancel , meta : getMeta ( ) } )
98
- }
125
+ } , [ onCancel , dispatch , getMeta ] )
99
126
127
+ /* These effects should only be triggered on changes to specific props */
128
+ /* eslint-disable react-hooks/exhaustive-deps */
100
129
const { watch, watchFn } = options
101
130
useEffect ( ( ) => {
102
131
if ( watchFn && lastOptions . current && watchFn ( options , lastOptions . current ) ) load ( )
@@ -108,19 +137,20 @@ const useAsync = (arg1, arg2) => {
108
137
} , [ promise , promiseFn , watch ] )
109
138
useEffect ( ( ) => ( ) => ( isMounted . current = false ) , [ ] )
110
139
useEffect ( ( ) => ( ) => cancel ( ) , [ ] )
140
+ /* eslint-enable react-hooks/exhaustive-deps */
111
141
112
142
useDebugValue ( state , ( { status } ) => `[${ counter . current } ] ${ status } ` )
113
143
114
144
return useMemo (
115
145
( ) => ( {
116
146
...state ,
117
- cancel,
118
147
run,
119
- reload : ( ) => ( lastArgs . current ? run ( ...lastArgs . current ) : load ( ) ) ,
148
+ reload,
149
+ cancel,
120
150
setData,
121
151
setError,
122
152
} ) ,
123
- [ state , deferFn , onResolve , onReject , dispatcher , reducer ]
153
+ [ state , run , reload , cancel , setData , setError ]
124
154
)
125
155
}
126
156
@@ -138,11 +168,12 @@ const useAsyncFetch = (input, init, { defer, json, ...options } = {}) => {
138
168
const doFetch = ( input , init ) => globalScope . fetch ( input , init ) . then ( parseResponse ( accept , json ) )
139
169
const isDefer = defer === true || ~ [ "POST" , "PUT" , "PATCH" , "DELETE" ] . indexOf ( method )
140
170
const fn = defer === false || ! isDefer ? "promiseFn" : "deferFn"
171
+ const identity = JSON . stringify ( { input, init } )
141
172
const state = useAsync ( {
142
173
...options ,
143
174
[ fn ] : useCallback (
144
175
( _ , props , ctrl ) => doFetch ( input , { signal : ctrl ? ctrl . signal : props . signal , ...init } ) ,
145
- [ JSON . stringify ( input ) , JSON . stringify ( init ) ]
176
+ [ identity ] // eslint-disable-line react-hooks/exhaustive-deps
146
177
) ,
147
178
} )
148
179
useDebugValue ( state , ( { counter, status } ) => `[${ counter } ] ${ status } ` )
0 commit comments