@@ -4,13 +4,41 @@ import { ActionEnum, StatusEnum } from './constants'
44import reducer from './reducer'
55
66const Actions = {
7- createReset : ( { data } ) => ( { type : ActionEnum . RESET , data } ) ,
7+ createReset : ( ) => ( { type : ActionEnum . RESET } ) ,
88 createOnLoading : ( ) => ( { type : ActionEnum . ON_LOADING } ) ,
9- createOnSuccess : data => ( { type : ActionEnum . ON_SUCCESS , data } ) ,
10- createOnUpdateData : data => ( { type : ActionEnum . ON_UPDATE_DATA , data } ) ,
9+ createOnSuccess : ( ) => ( { type : ActionEnum . ON_SUCCESS } ) ,
1110 createOnError : error => ( { type : ActionEnum . ON_ERROR , error } ) ,
1211}
1312
13+ /**
14+ * @typedef {Object } useDataLoaderConfig
15+ * @property {Function } [onSuccess] callback when a request success
16+ * @property {Function } [onError] callback when a error is occured
17+ * @property {* } [initialData] initial data if no one is present in the cache before the request
18+ * @property {number } [pollingInterval] relaunch the request after the last success
19+ * @property {boolean } [enabled=true] launch request automatically (default true)
20+ * @property {boolean } [keepPreviousData=true] do we need to keep the previous data after reload (default true)
21+ */
22+
23+ /**
24+ * @typedef {Object } useDataLoaderResult
25+ * @property {boolean } isIdle true if the hook in initial state
26+ * @property {boolean } isLoading true if the request is launched
27+ * @property {boolean } isSuccess true if the request success
28+ * @property {boolean } isError true if the request throw an error
29+ * @property {boolean } isPolling true if the request if enabled is true, pollingInterval is defined and the status is isLoading or isSuccess
30+ * @property {* } previousData if keepPreviousData is true it return the last data fetched
31+ * @property {* } data initialData if no data is fetched or not present in the cache otherwise return the data fetched
32+ * @property {string } error the error occured during the request
33+ * @property {Function } reload reload the data
34+ */
35+
36+ /**
37+ * @param {string } key key to save the data fetched in a local cache
38+ * @param {() => Promise } method a method that return a promise
39+ * @param {useDataLoaderConfig } config hook configuration
40+ * @returns {useDataLoaderResult } hook result containing data, request state, and method to reload the data
41+ */
1442const useDataLoader = (
1543 key ,
1644 method ,
@@ -20,7 +48,6 @@ const useDataLoader = (
2048 initialData,
2149 pollingInterval,
2250 enabled = true ,
23- reloadOnKeyChange = true ,
2451 keepPreviousData = true ,
2552 } = { } ,
2653) => {
@@ -30,14 +57,13 @@ const useDataLoader = (
3057 clearReload,
3158 getCachedData,
3259 } = useDataLoaderContext ( )
33- const [ { status, data , error } , dispatch ] = useReducer ( reducer , {
60+ const [ { status, error } , dispatch ] = useReducer ( reducer , {
3461 status : StatusEnum . IDLE ,
35- data : initialData ,
3662 error : undefined ,
3763 } )
3864
3965 const previousDataRef = useRef ( )
40- const keyRef = useRef ( )
66+ const keyRef = useRef ( key )
4167 const methodRef = useRef ( method )
4268 const onSuccessRef = useRef ( onSuccess )
4369 const onErrorRef = useRef ( onError )
@@ -46,26 +72,28 @@ const useDataLoader = (
4672 const isIdle = useMemo ( ( ) => status === StatusEnum . IDLE , [ status ] )
4773 const isSuccess = useMemo ( ( ) => status === StatusEnum . SUCCESS , [ status ] )
4874 const isError = useMemo ( ( ) => status === StatusEnum . ERROR , [ status ] )
75+
4976 const isPolling = useMemo (
5077 ( ) => enabled && pollingInterval && ( isSuccess || isLoading ) ,
5178 [ isSuccess , isLoading , enabled , pollingInterval ] ,
5279 )
5380
54- const handleRequest = useRef ( async ( cacheKey , args ) => {
55- const cachedData = getCachedData ( cacheKey )
56- if ( cacheKey && ! data && cachedData ) {
57- dispatch ( Actions . createOnUpdateData ( cachedData ) )
58- }
81+ const handleRequest = useRef ( async cacheKey => {
5982 try {
6083 dispatch ( Actions . createOnLoading ( ) )
61- const result = await methodRef . current ?. ( args )
84+ const result = await methodRef . current ?. ( )
6285
63- if ( result && cacheKey ) addCachedData ( cacheKey , result )
6486 if ( keyRef . current && cacheKey && cacheKey !== keyRef . current ) {
6587 return
6688 }
6789
68- dispatch ( Actions . createOnSuccess ( result ) )
90+ if ( keepPreviousData ) {
91+ previousDataRef . current = getCachedData ( cacheKey )
92+ }
93+ if ( result !== undefined && result !== null && cacheKey )
94+ addCachedData ( cacheKey , result )
95+
96+ dispatch ( Actions . createOnSuccess ( ) )
6997
7098 await onSuccessRef . current ?. ( result )
7199 } catch ( err ) {
@@ -77,19 +105,15 @@ const useDataLoader = (
77105 useEffect ( ( ) => {
78106 let handler
79107 if ( enabled ) {
80- if (
81- reloadOnKeyChange &&
82- key !== keyRef . current &&
83- status !== StatusEnum . IDLE
84- ) {
108+ if ( ! isIdle && keyRef . current !== key ) {
85109 keyRef . current = key
86- dispatch ( Actions . createReset ( { data : initialData } ) )
110+ dispatch ( Actions . createReset ( ) )
87111 } else {
88- if ( status === StatusEnum . IDLE ) {
112+ if ( isIdle ) {
89113 keyRef . current = key
90114 handleRequest . current ( key )
91115 }
92- if ( pollingInterval && status === StatusEnum . SUCCESS ) {
116+ if ( pollingInterval && isSuccess && ! handler ) {
93117 handler = setTimeout (
94118 ( ) => handleRequest . current ( key ) ,
95119 pollingInterval ,
@@ -107,38 +131,34 @@ const useDataLoader = (
107131 }
108132 if ( handler ) {
109133 clearTimeout ( handler )
134+ handler = undefined
110135 }
111136 }
112137 // Why can't put empty array for componentDidMount, componentWillUnmount ??? No array act like componentDidMount and componentDidUpdate
113138 } , [
114139 enabled ,
115- pollingInterval ,
116140 key ,
117141 clearReload ,
118142 addReload ,
119- status ,
120- reloadOnKeyChange ,
121- initialData ,
143+ addCachedData ,
144+ getCachedData ,
145+ pollingInterval ,
146+ isIdle ,
147+ isSuccess ,
122148 ] )
123149
124150 useLayoutEffect ( ( ) => {
125151 methodRef . current = method
126152 } , [ method ] )
127153
128- useLayoutEffect ( ( ) => {
129- if ( keepPreviousData && data && previousDataRef . current !== data ) {
130- previousDataRef . current = data
131- }
132- } , [ keepPreviousData , data ] )
133-
134154 return {
135155 isLoading,
136156 isIdle,
137157 isSuccess,
138158 isError,
139159 isPolling,
140160 previousData : previousDataRef . current ,
141- data,
161+ data : getCachedData ( key ) || initialData ,
142162 error,
143163 reload : args => handleRequest . current ( key , args ) ,
144164 }
0 commit comments