@@ -7,14 +7,22 @@ import { getRequestKey, fetchDedupe, isRequestInFlight } from 'fetch-dedupe';
77// The value of each key is a Response instance
88let responseCache = { } ;
99
10+ // The docs state that this is not safe to use in an
11+ // application. That's just because I am not writing tests,
12+ // nor designing the API, around folks clearing the cache.
13+ // This was only added to help out with testing your app.
14+ // Use your judgment if you decide to use this in your
15+ // app directly.
1016export function clearResponseCache ( ) {
1117 responseCache = { } ;
1218}
1319
1420export class Fetch extends React . Component {
1521 render ( ) {
16- const { children, requestName, url } = this . props ;
17- const { fetching, response, data, error, requestKey } = this . state ;
22+ // Anything pulled from `this.props` here is not eligible to be
23+ // specified when calling `doFetch`.
24+ const { children, requestName } = this . props ;
25+ const { fetching, response, data, error, requestKey, url } = this . state ;
1826
1927 if ( ! children ) {
2028 return null ;
@@ -49,7 +57,8 @@ export class Fetch extends React.Component {
4957 fetching : false ,
5058 response : null ,
5159 data : null ,
52- error : null
60+ error : null ,
61+ url : props . url
5362 } ;
5463 }
5564
@@ -95,22 +104,27 @@ export class Fetch extends React.Component {
95104 }
96105 }
97106
98- componentWillReceiveProps ( nextProps ) {
107+ // Because we use `componentDidUpdate` to determine if we should fetch
108+ // again, there will be at least one render when you receive your new
109+ // fetch options, such as a new URL, but the fetch has not begun yet.
110+ componentDidUpdate ( prevProps ) {
99111 const currentRequestKey =
100112 this . props . requestKey ||
101113 getRequestKey ( {
102114 ...this . props ,
103115 method : this . props . method . toUpperCase ( )
104116 } ) ;
105- const nextRequestKey =
106- nextProps . requestKey ||
117+ const prevRequestKey =
118+ prevProps . requestKey ||
107119 getRequestKey ( {
108- ...nextProps ,
109- method : this . props . method . toUpperCase ( )
120+ ...prevProps ,
121+ method : prevProps . method . toUpperCase ( )
110122 } ) ;
111123
112- if ( currentRequestKey !== nextRequestKey && ! this . isLazy ( nextProps ) ) {
113- this . fetchData ( nextProps ) ;
124+ if ( currentRequestKey !== prevRequestKey && ! this . isLazy ( prevProps ) ) {
125+ this . fetchData ( {
126+ requestKey : currentRequestKey
127+ } ) ;
114128 }
115129 }
116130
@@ -124,6 +138,8 @@ export class Fetch extends React.Component {
124138 cancelExistingRequest = reason => {
125139 if ( this . state . fetching && ! this . hasHandledNetworkResponse ) {
126140 const abortError = new Error ( reason ) ;
141+ // This is an effort to mimic the error that is created when a
142+ // fetch is actually aborted using the AbortController API.
127143 abortError . name = 'AbortError' ;
128144 this . onResponseReceived ( {
129145 ...this . responseReceivedInfo ,
@@ -145,11 +161,57 @@ export class Fetch extends React.Component {
145161 } ) ;
146162 } ;
147163
164+ // When a subsequent request is made, it is important that the correct
165+ // request key is used. This method computes the right key based on the
166+ // options and props.
167+ getRequestKey = options => {
168+ // A request key in the options gets top priority
169+ if ( options && options . requestKey ) {
170+ return options . requestKey ;
171+ }
172+
173+ // Otherwise, if we have no request key, but we do have options, then we
174+ // recompute the request key based on these options.
175+ // Note that if the URL, body, or method have not changed, then the request
176+ // key should match the previous request key if it was computed.
177+ // If you passed in a custom request key as a prop, then you will also
178+ // need to pass in a custom key when you call `doFetch()`!
179+ else if ( options ) {
180+ const { url, method, body } = Object . assign ( { } , this . props , options ) ;
181+ return getRequestKey ( {
182+ url,
183+ body,
184+ method : method . toUpperCase ( )
185+ } ) ;
186+ }
187+
188+ // Next in line is the the request key from props.
189+ else if ( this . props . requestKey ) {
190+ return this . props . requestKey ;
191+ }
192+
193+ // Lastly, we compute the request key from the props.
194+ else {
195+ const { url, method, body } = this . props ;
196+
197+ return getRequestKey ( {
198+ url,
199+ body,
200+ method : method . toUpperCase ( )
201+ } ) ;
202+ }
203+ } ;
204+
148205 fetchData = ( options , ignoreCache ) => {
206+ // These are the things that we do not allow a user to configure in
207+ // `options` when calling `doFetch()`. Perhaps we should, however.
149208 const { requestName, dedupe, beforeFetch } = this . props ;
150209
151210 this . cancelExistingRequest ( 'New fetch initiated' ) ;
152211
212+ const requestKey = this . getRequestKey ( options ) ;
213+ const requestOptions = Object . assign ( { } , this . props , options ) ;
214+
153215 const {
154216 url,
155217 body,
@@ -165,16 +227,7 @@ export class Fetch extends React.Component {
165227 integrity,
166228 keepalive,
167229 signal
168- } = Object . assign ( { } , this . props , options ) ;
169-
170- // We need to compute a new key, just in case a new value was passed in `doFetch`.
171- const requestKey =
172- this . props . requestKey ||
173- getRequestKey ( {
174- url,
175- method : method . toUpperCase ( ) ,
176- body
177- } ) ;
230+ } = requestOptions ;
178231
179232 const uppercaseMethod = method . toUpperCase ( ) ;
180233 const shouldCacheResponse = this . shouldCacheResponse ( ) ;
@@ -205,6 +258,7 @@ export class Fetch extends React.Component {
205258 // If the request config changes, we need to be able to accurately
206259 // cancel the in-flight request.
207260 this . responseReceivedInfo = responseReceivedInfo ;
261+
208262 this . hasHandledNetworkResponse = false ;
209263
210264 const fetchPolicy = this . getFetchPolicy ( ) ;
@@ -238,8 +292,11 @@ export class Fetch extends React.Component {
238292 }
239293
240294 this . setState ( {
241- fetching : true ,
242- requestKey
295+ requestKey,
296+ url,
297+ error : null ,
298+ failed : false ,
299+ fetching : true
243300 } ) ;
244301 const hittingNetwork = ! isRequestInFlight ( requestKey ) || ! dedupe ;
245302
@@ -331,10 +388,12 @@ export class Fetch extends React.Component {
331388
332389 this . setState (
333390 {
391+ url,
334392 data,
335393 error,
336394 response,
337- fetching : stillFetching
395+ fetching : stillFetching ,
396+ requestKey
338397 } ,
339398 ( ) => this . props . onResponse ( error , response )
340399 ) ;
0 commit comments