@@ -74,6 +74,7 @@ yarn add react-http-fetch
7474You can override the default configuration used by the http client to perform any request by using the ` HttpClientConfigProvider ` :
7575
7676``` js
77+ import React from ' react' ;
7778import { defaultHttpReqConfig , HttpClientConfigProvider } from ' react-http-fetch' ;
7879
7980function Child () {
@@ -128,9 +129,9 @@ Below the complete set of options you can provide to the `HttpClientConfigProvid
128129The ` useHttpClient ` hook return a set of methods to perform http requests. The ` request ` function is the lowest level one, all other exposed functions are just decorators around it. Below a basic example using ` request ` :
129130
130131``` js
132+ import React from ' react' ;
131133import { useHttpClient } from ' react-http-fetch' ;
132134
133-
134135function App () {
135136 const { request } = useHttpClient ();
136137
@@ -311,6 +312,7 @@ Returns an array of two elements, the first one embeds the state of the http req
311312
312313### Example &ndash ; Http request hook triggered automatically on component mount
313314``` js
315+ import React from ' react' ;
314316import { useHttpRequest } from ' react-http-fetch' ;
315317
316318function App () {
@@ -335,7 +337,7 @@ export default App;
335337### Example &ndash ; Http request hook triggered manually on component mount
336338``` js
337339import { useHttpRequest } from ' react-http-fetch' ;
338- import { useEffect } from ' react' ;
340+ import React , { useEffect } from ' react' ;
339341
340342function App () {
341343 const [state , request ] = useHttpRequest ({
@@ -355,6 +357,74 @@ export default App;
355357
356358### Example &ndash ; Http post request hook
357359
360+ ``` js
361+ import React , { useState } from ' react' ;
362+ import { useHttpPost } from ' react-http-fetch' ;
363+
364+ function App () {
365+ const [inputs , setInputs ] = useState ({});
366+
367+ const handleChange = (event ) => {
368+ const name = event .target .name ;
369+ const value = event .target .value ;
370+ setInputs (values => ({... values, [name]: value}))
371+ }
372+
373+ const [, createPostRequest ] = useHttpPost ({
374+ baseUrlOverride: ' https://jsonplaceholder.typicode.com' ,
375+ relativeUrl: ' posts' ,
376+ });
377+
378+ const createPost = async (event ) => {
379+ event .preventDefault ();
380+ const { postTitle , postBody } = inputs;
381+
382+ const reqBody = { title: postTitle, body: postBody };
383+ try {
384+ // Providing request options when running the request.
385+ // Provided options will be merged to the one provided
386+ // to the hook useHttpPost.
387+ await createPostRequest ({
388+ requestOptions: { body: reqBody }
389+ });
390+ alert (' Post created!' );
391+ } catch (error) {
392+ console .error (error);
393+ alert (' An error occured. Check the browser console.' );
394+ }
395+ };
396+
397+ return (
398+ < form onSubmit= {createPost}>
399+ < label style= {{ display: ' block' }}>
400+ Title:
401+ < input
402+ type= " text"
403+ name= " postTitle"
404+ value= {inputs .postTitle || " " }
405+ onChange= {handleChange}
406+ / >
407+ < / label>
408+ < label style= {{ display: ' block' }}>
409+ Body:
410+ < input
411+ type= " text"
412+ name= " postBody"
413+ value= {inputs .postBody || " " }
414+ onChange= {handleChange}
415+ / >
416+ < / label>
417+ < button type= " submit" >
418+ Create Post
419+ < / button>
420+ < / form>
421+ );
422+ }
423+
424+ export default App ;
425+ ```
426+
427+
358428<br >
359429
360430## Events
@@ -366,7 +436,7 @@ Every time a request is executed the events shown below will be emitted. Each ev
366436| [ RequestErroredEvent] ( src/events-manager/events/request-errored-event.ts ) | [ HttpError] ( src/errors/http-error.ts ) |
367437| [ RequestSuccededEvent] ( src/events-manager/events/request-succeded-event.ts ) | [ RequestSuccededEventPayload] ( src/events-manager/events/request-succeded-event.ts ) |
368438
369- It's possible to subscribe a specific event using the [ useHttpEvent] ( src/events-manager/use-http-event.ts ) hook as shown below:
439+ You can subscribe a specific event using the [ useHttpEvent] ( src/events-manager/use-http-event.ts ) hook as shown below:
370440
371441``` js
372442import { useState } from ' react' ;
@@ -398,6 +468,207 @@ export default App;
398468<br >
399469
400470## Caching
471+ Any request can be cached by setting the ` maxAge ` (expressed in milliseconds) parameter as part of the reuqest options as shown below:
472+
473+ ``` js
474+ import { useHttpRequest } from ' react-http-fetch' ;
475+ import React from ' react' ;
476+
477+ function App () {
478+ const [state , request ] = useHttpRequest ({
479+ baseUrlOverride: ' https://jsonplaceholder.typicode.com' ,
480+ relativeUrl: ' todos/1' ,
481+ requestOptions: { maxAge: 60000 } // Cache for 1 minute
482+ });
483+
484+ const fetchTodo = () => {
485+ const { reqResult } = request ();
486+ reqResult .then (res => console .log (res))
487+ };
488+
489+ return (
490+ <>
491+ < div>
492+ {` Todo name: ${ (state && state .data && state .data .title ) || ' ' } ` }
493+ < / div>
494+ < button type= " button" onClick= {fetchTodo}>
495+ Make request
496+ < / button>
497+ < / >
498+ );
499+ }
500+
501+ export default App ;
502+ ```
503+
504+ By default the http client uses an in-memory cache, so it will be flushed everytime a full app refresh is performed. You can override the default caching strategy by providing your own cache. The example below a http cache based on session storage:
505+
506+ ``` js
507+ import React from ' react' ;
508+ import { HttpClientConfigProvider , HttpCache , useHttpRequest } from ' react-http-fetch' ;
509+
510+ export class HttpSessionStorageCacheService extends HttpCache {
511+ /**
512+ * The local cache providing for a request identifier
513+ * the corresponding parsed response.
514+ */
515+ store = window .sessionStorage ;
516+
517+ /**
518+ * Gets the unique key used as idenitifier to store
519+ * a cached response for the given http request.
520+ */
521+ _getRequestIdentifier (request ) {
522+ const fullUrl = request .urlWithParams ;
523+ return fullUrl;
524+ }
525+
526+ /**
527+ * Tells if a cached entry is expired.
528+ */
529+ _isEntryExpired (entry ) {
530+ const nowTime = new Date ().getTime ();
531+ const cachedAt = entry .cachedAt instanceof Date ? entry .cachedAt : new Date (entry .cachedAt );
532+ const cachedTime = cachedAt .getTime ();
533+ return cachedTime + entry .maxAge < nowTime;
534+ }
535+
536+ /**
537+ * Gets the cached entry associated with the request.
538+ */
539+ _getEntry (request ) {
540+ const reqIdentifier = this ._getRequestIdentifier (request);
541+ const storedEntry = this .store .getItem (reqIdentifier);
542+
543+ try {
544+ const parsedEntry = JSON .parse (storedEntry);
545+ return parsedEntry;
546+ } catch (err) {
547+ return null ;
548+ }
549+ }
550+
551+ /**
552+ * Removes a cached entry.
553+ */
554+ _removeEntry (entry ) {
555+ this .store .removeItem (entry .identifier );
556+ }
557+
558+ /**
559+ * Determines if for the given request is available a cached response.
560+ */
561+ _has (request ) {
562+ const key = this ._getRequestIdentifier (request);
563+ return this .store .hasOwnProperty (key);
564+ }
565+
566+ /**
567+ * Tells if the cached request is expired or not.
568+ */
569+ _isExpired (request ) {
570+ const cachedEntry = this ._getEntry (request);
571+ if (! cachedEntry) {
572+ return true ;
573+ }
574+
575+ return this ._isEntryExpired (cachedEntry);
576+ }
577+
578+ /**
579+ * Gets the cached entry in the map for the given request.
580+ */
581+ get (request ) {
582+ const cachedEntry = this ._getEntry (request);
583+ if (! cachedEntry) {
584+ return undefined ;
585+ }
586+
587+ const isExpired = this ._isEntryExpired (cachedEntry);
588+ return isExpired ? undefined : cachedEntry .response ;
589+ }
590+
591+ /**
592+ * Puts a new cached response for the given request.
593+ */
594+ put (request , response ) {
595+ if (! request .maxAge ) {
596+ return ;
597+ }
598+
599+ const reqKey = this ._getRequestIdentifier (request);
600+ const entry = {
601+ response,
602+ identifier: reqKey,
603+ cachedAt: new Date (),
604+ maxAge: request .maxAge ,
605+ };
606+
607+ // Update and flush the cache.
608+ this .store .setItem (reqKey, JSON .stringify (entry));
609+
610+ // Remove the entry from the cache once expired.
611+ const timerRef = setTimeout (() => {
612+ this ._removeEntry (entry);
613+ clearTimeout (timerRef);
614+ }, request .maxAge );
615+ }
616+
617+ /**
618+ * Founds all expired entry and deletes them from the cache.
619+ */
620+ flush () {
621+ this .store .forEach ((entry ) => {
622+ const isEntryExpired = this ._isEntryExpired (entry);
623+
624+ if (isEntryExpired) {
625+ this ._removeEntry (entry);
626+ }
627+ });
628+ }
629+ }
630+
631+ const httpCache = new HttpSessionStorageCacheService ();
632+
633+ function Child () {
634+ const [state , request ] = useHttpRequest ({
635+ baseUrlOverride: ' https://jsonplaceholder.typicode.com' ,
636+ relativeUrl: ' todos/1' ,
637+ requestOptions: { maxAge: 60000 } // Cache for 1 minute
638+ });
639+
640+ console .log (' Request state:' , state .data );
641+
642+ const fetchTodo = () => {
643+ const { reqResult } = request ();
644+ reqResult .then (res => console .log (' Request res: ' , res))
645+ };
646+
647+ return (
648+ <>
649+ < div>
650+ {` Todo name: ${ (state && state .data && state .data .title ) || ' ' } ` }
651+ < / div>
652+ < button type= " button" onClick= {fetchTodo}>
653+ Make request
654+ < / button>
655+ < / >
656+ );
657+ };
658+
659+
660+ function App () {
661+ const httpReqConfig = { cache: httpCache };
662+
663+ return (
664+ < HttpClientConfigProvider config= {httpReqConfig}>
665+ < Child / >
666+ < / HttpClientConfigProvider>
667+ );
668+ }
669+
670+ export default App ;
671+ ```
401672
402673<br >
403674
0 commit comments