Skip to content

Repository files navigation

React http fetch

react-http-fetch logo
A http library for React JS built on top of JS native fetch.

Contributing Guidelines · Changelog

Build statusreact-http-fetch on npmMIT license



Contents

Just follow links below to get an overview of library features.


Getting started

Install the package by using npm

npm install react-http-fetch

or yarn

yarn add react-http-fetch

Provider

You can override the default configuration used by the http client to perform any request by using the HttpClientConfigProvider:

importReactfrom'react';import{defaultHttpReqConfig,HttpClientConfigProvider}from'react-http-fetch';functionChild(){return(<div> Child component </div>);};functionhttpResponseParser(res){returnres.json();}functionApp(){/** * Provided configs are automatically merged to the default one. */consthttpReqConfig={// ...defaultHttpReqConfig,baseUrl: process.env.BACKEND_URL,responseParser: httpResponseParser,reqOptions: {headers: {'Content-Type': 'text/html; charset=UTF-8',},},};return(<HttpClientConfigProviderconfig={httpReqConfig}><Child/></HttpClientConfigProvider>);}exportdefaultApp;

Below the complete set of options you can provide to the HttpClientConfigProvider:

OptionDescriptionDefault
baseUrlThe base url used by the client to perform any http request (e.g. http://localhost:8000)''
responseParserA function that maps the native fetch response. The default parser transform the fetch response stream into a json (https://developer.mozilla.org/en-US/docs/Web/API/Response/json)httpResponseParser
requestBodySerializerA function used to serialize request body. The default serializer take into account a wide range of data types to figure out which type of serialization to performserializeRequestBody
reqOptionsThe default request option that will be carried by any request dispatched by the client. See HttpRequestOptions{ headers: { 'Content-Type': 'application/json' } }
cacheStoreThe store for cached http responses. By default an in-memory cache store is used.HttpInMemoryCacheStore
cacheStorePrefixThe prefix concatenated to any cached entry.rfh
cacheStoreSeparatorSeparates the store prefix and the cached entry identifier__

Http client

The 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:

importReactfrom'react';import{useHttpClient}from'react-http-fetch';functionApp(){const{ request }=useHttpClient();const[todo,setTodo]=useState();useEffect(()=>{constfetchTodo=async()=>{constres=awaitrequest({baseUrlOverride: 'https://jsonplaceholder.typicode.com',relativeUrl: 'todos/1',requestOptions: {method: 'GET',},});setTodo(res);};fetchTodo();},[request]);return(<div>{`Todo name: ${todo&&todo.title}`}</div>);}exportdefaultApp;

Public API

The complete public API exposed by the hook:

MethodDescriptionParamsReturn
requestThe lowest level method to perform a http requestRequest paramsRequest return
  • get
  • post
  • put
  • patch
  • delete
Make use of lower level method request by just overriding the http method (example)Request paramsRequest return
abortableRequestThe lowest level method to perform an abortable http request (example)Request paramsAbortable request return
  • abortableGet
  • abortablePost
  • abortablePut
  • abortablePatch
  • abortableDelete
Make use of lower level method abortableRequest by just overriding the http methodRequest paramsAbortable request return

Request params

ParameterTypeDescription
baseUrlOverridestringThe base url of the request. If provided, it would override the provider base url.
relativeUrlstringThe url relative to the base one (e.g. posts/1).
parserHttpResponseParserAn optional response parser that would override the provider global one.
contextHttpContextAn optional context that carries arbitrary user defined data. See examples.
requestOptionsHttpRequestOptionsThe options carried by the fetch request.

Request return

The jsonified return value of native JS fetch. If a custom response parser (see Provider) is provided then the return value corresponds to the parsed one.

Abortable request return

ValueType
[request, abortController][RequestReturn, AbortController]

Example – Abortable request

importReact,{useState,useRef}from'react';import{useHttpClient}from'react-http-fetch';functionApp(){const{ abortableRequest }=useHttpClient();constabortCtrlRef=useRef();const[todo,setTodo]=useState();constfetchTodo=async()=>{const[reqPromise,abortController]=abortableRequest({baseUrlOverride: 'https://jsonplaceholder.typicode.com',relativeUrl: 'todos/1',});abortCtrlRef.current=abortController;try{constres=awaitreqPromise;setTodo(res);}catch(error){// Abort the request will cause the request promise to be rejected with the following error:// "DOMException: The user aborted a request."console.error(error);}finally{abortCtrlRef.current=undefined;}};constabortPendingRequest=()=>{if(abortCtrlRef.current){abortCtrlRef.current.abort();}};return(<divstyle={{margin: '20px'}}><div>{`Todo name: ${todo&&todo.title}`}</div><buttonstyle={{marginRight: '10px'}}type="button"onClick={fetchTodo}>
Do request
</button><buttontype="button"onClick={abortPendingRequest}>
Abort
</button></div>);}exportdefaultApp;

Example – Get request

importReact,{useState,useEffect}from'react';import{useHttpClient}from'react-http-fetch';functionApp(){const{ get }=useHttpClient();const[todo,setTodo]=useState();useEffect(()=>{constfetchTodo=async()=>{constres=awaitget({baseUrlOverride: 'https://jsonplaceholder.typicode.com',relativeUrl: 'todos/1',});setTodo(res);};fetchTodo();},[get]);return(<div>{`Todo name: ${todo&&todo.title}`}</div>);}exportdefaultApp;

Example – Http context

importReact,{useEffect}from'react';import{useHttpClient,useHttpEvent,RequestStartedEvent,HttpContextToken,HttpContext,}from'react-http-fetch';constshowGlobalLoader=newHttpContextToken(true);constreqContext=newHttpContext().set(showGlobalLoader,false);functionApp(){const{ request }=useHttpClient();useHttpEvent(RequestStartedEvent,(payload)=>{console.log('Show global loader:',payload.context.get(showGlobalLoader));});useEffect(()=>{constfetchTodo=async()=>{awaitrequest({baseUrlOverride: 'https://jsonplaceholder.typicode.com',relativeUrl: 'todos/1',context: reqContext,});};fetchTodo();},[request]);return(<h1>Http Context</h1>);}exportdefaultApp;

Request hooks

The library provides a hook useHttpRequest managing the state of the http request. Such state is returned by the hook along with a function to trigger the request. See params and return for more info. A dedicated hook is provided for every http method: useHttpGet, useHttpPost, useHttpPatch, useHttpPut, useHttpDelete.

Http request hook params

ParameterTypeDescription
baseUrlOverridestringThe base url of the request. If provided, it would override the provider base url.
relativeUrlstringThe url relative to the base one (e.g. posts/1).
parserHttpResponseParserAn optional response parser that would override the provider global one.
contextHttpContextAn optional context that carries arbitrary user defined data. See examples.
requestOptionsHttpRequestOptionsThe options carried by the fetch request.
initialDataanyThe value that the state assumes initially before the request is send.
fetchOnBootstrapbooleanTell if the fetch must be triggered automatically when mounting the component or not. In the second case we would like to have a manual fetch, this is optained by a request function returned by the hook.

Http request hook return

Returns an array of three elements:

  • The first one embeds the state of the http request.
  • The second is a function that can be used to perform an abortable http request.
  • The third is a function that can be used to perform a non-abortable http request.

See examples for further details. The table below describes the shape (i.e. properties) of http request state.

Http request state

PropertyTypeDescription
pristinebooleanTells if the request has been dispatched.
erroredbooleanTells if the request has returned an error.
isLoadingbooleanTells if the request is pending.
errorunknownproperty evaluated by the error generated by the backend api.
dataanyThe response provided by the backend api.

Example – Http request hook triggered automatically on component mount

importReactfrom'react';import{useHttpRequest}from'react-http-fetch';functionApp(){const[state]=useHttpRequest({baseUrlOverride: 'https://jsonplaceholder.typicode.com',relativeUrl: 'todos/1',requestOptions: {},initialData: {},fetchOnBootstrap: true,});return(<div>{`Todo name: ${(state.data&&state.data.title)||'unknown'}`}</div>);}exportdefaultApp;

Example – Http request hook triggered manually on component mount

import{useHttpRequest}from'react-http-fetch';importReact,{useEffect}from'react';functionApp(){const[state,request]=useHttpRequest({baseUrlOverride: 'https://jsonplaceholder.typicode.com',relativeUrl: 'todos/1',});useEffect(()=>{const{ reqResult, abortController }=request();reqResult.then(res=>console.log('request response',res)).catch(err=>console.error(err));// You can use the returned AbortController instance to abort the request// abortController.abort();},[request]);return(<div>{`Todo name: ${(state.data&&state.data.title)||'unknown'}`}</div>);}exportdefaultApp;

Example – Non-abortable http request hook

PlaceholderimportReact,{useEffect}from'react';import{useHttpRequest}from'react-http-fetch';functionApp(){const[state,,request]=useHttpRequest({baseUrlOverride: 'https://jsonplaceholder.typicode.com',relativeUrl: 'todos/1',});useEffect(()=>request(),[request]);return(<div>{`Todo name: ${(state.data&&state.data.title)||'unknown'}`}</div>);}exportdefaultApp;

Example – Aborting http request triggered by the hook

import{useHttpRequest}from'react-http-fetch';importReact,{useRef}from'react';functionApp(){const[state,request]=useHttpRequest({baseUrlOverride: 'https://jsonplaceholder.typicode.com',relativeUrl: 'todos/1',});constabortCtrlRef=useRef();constfetchTodo=()=>{abortPendingRequest();const{ reqResult, abortController }=request();abortCtrlRef.current=abortController;reqResult// Abort the request will cause the request promise to be rejected with the following error:// "DOMException: The user aborted a request.".catch(err=>console.error(err));};constabortPendingRequest=()=>{if(abortCtrlRef.current){abortCtrlRef.current.abort();}};return(<divstyle={{margin: '20px'}}><div>{`Todo name: ${(state.data&&state.data.title)||'unknown'}`}</div><buttonstyle={{marginRight: '10px'}}type="button"onClick={fetchTodo}>
Do request
</button><buttontype="button"onClick={abortPendingRequest}>
Abort
</button></div>);}exportdefaultApp;

Example – Http post request hook

importReact,{useState}from'react';import{useHttpPost}from'react-http-fetch';functionApp(){const[inputs,setInputs]=useState({});consthandleChange=(event)=>{constname=event.target.name;constvalue=event.target.value;setInputs(values=>({...values,[name]: value}))}const[,createPostRequest]=useHttpPost({baseUrlOverride: 'https://jsonplaceholder.typicode.com',relativeUrl: 'posts',});constcreatePost=async(event)=>{event.preventDefault();const{ postTitle, postBody }=inputs;constreqBody={title: postTitle,body: postBody};try{// Providing request options when running the request.// Provided options will be merged to the one provided// to the hook useHttpPost.awaitcreatePostRequest({requestOptions: {body: reqBody}});alert('Post created!');}catch(error){console.error(error);alert('An error occured. Check the browser console.');}};return(<formonSubmit={createPost}><labelstyle={{display: 'block'}}>
Title:
<inputtype="text"name="postTitle"value={inputs.postTitle||""}onChange={handleChange}/></label><labelstyle={{display: 'block'}}>
Body:
<inputtype="text"name="postBody"value={inputs.postBody||""}onChange={handleChange}/></label><buttontype="submit">
Create Post
</button></form>);}exportdefaultApp;

Events

Every time a request is executed the events shown below will be emitted. Each event carries a specific payload.

Event typePayload type
RequestStartedEventHttpRequest
RequestErroredEventHttpError
RequestSuccededEventRequestSuccededEventPayload

You can subscribe a specific event using the useHttpEvent hook as shown below:

import{useState}from'react';import{RequestErroredEvent,RequestStartedEvent,RequestSuccededEvent,useHttpEvent,useHttpRequest}from'react-http-fetch';functionApp(){const[count,setCount]=useState(0);const[,request]=useHttpRequest({baseUrlOverride: 'https://jsonplaceholder.typicode.com',relativeUrl: 'todos/1',});useHttpEvent(RequestStartedEvent,()=>setCount(count+1));useHttpEvent(RequestSuccededEvent,()=>setCount(count>0 ? count-1 : 0));useHttpEvent(RequestErroredEvent,()=>setCount(count>0 ? count-1 : 0));return(<><buttononClick={request}>{'increment count:'}</button><span>{count}</span></>);}exportdefaultApp;

Caching

Any request can be cached by setting the maxAge (expressed in milliseconds) parameter as part of the request options as shown below:

import{useHttpRequest}from'react-http-fetch';importReactfrom'react';functionApp(){const[state,request]=useHttpRequest({baseUrlOverride: 'https://jsonplaceholder.typicode.com',relativeUrl: 'todos/1',requestOptions: {maxAge: 60000}// Cache for 1 minute});constfetchTodo=()=>{const{ reqResult }=request();reqResult.then(res=>console.log(res))};return(<><div>{`Todo name: ${(state&&state.data&&state.data.title)||''}`}</div><buttontype="button"onClick={fetchTodo}>
Make request
</button></>);}exportdefaultApp;

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 store. The example below shows a http cache store based on session storage:

importReactfrom'react';import{useHttpRequest,HttpClientConfigProvider}from'react-http-fetch';exportclassHttpSessionStorageCacheStore{/** * The local cache providing for a request identifier * the corresponding cached entry. */_store=window.sessionStorage;/** * @inheritdoc */get(identifier){conststringifiedEntry=this._store.getItem(identifier);if(!stringifiedEntry){return;}try{constparsedEntry=JSON.parse(stringifiedEntry);returnparsedEntry;}catch(err){return;}}/** * @inheritdoc */put(identifier,entry){try{conststringifiedEntry=JSON.stringify(entry);this._store.setItem(identifier,stringifiedEntry);return()=>this.delete(identifier);}catch(err){return()=>{};}}/** * @inheritdoc */has(identifier){returnthis._store.has(identifier);}/** * @inheritdoc */delete(identifier){this._store.removeItem(identifier);}/** * Gets all entry keys. */_keys(){returnObject.keys(this._store);}/** * Gets all stored entries. */entries(){returnthis._keys().map(entryKey=>this._store.getItem(entryKey));}/** * @inheritdoc */flush(){this._keys().forEach((itemKey)=>{this.delete(itemKey);});}}consthttpCacheStore=newHttpSessionStorageCacheStore();functionChild(){const[state,request]=useHttpRequest({baseUrlOverride: 'https://jsonplaceholder.typicode.com',relativeUrl: 'todos/1',requestOptions: {maxAge: 60000}// Cache for 1 minute});console.log('Request state:',state.data);constfetchTodo=()=>{const{ reqResult }=request();reqResult.then(res=>console.log('Request response: ',res))};return(<><div>{`Todo name: ${(state&&state.data&&state.data.title)||''}`}</div><buttontype="button"onClick={fetchTodo}>
Make request
</button></>);};functionApp(){consthttpReqConfig={cacheStore: httpCacheStore,// "prefix" and "separator" are not mandatory,// if not provided the default ones will be used.cacheStorePrefix: 'customPrefix',cacheStoreSeparator: '-'};return(<HttpClientConfigProviderconfig={httpReqConfig}><Child/></HttpClientConfigProvider>);}exportdefaultApp;

Browser support

Edge
Edge
Firefox
Firefox
Chrome
Chrome
Safari
Safari
last 2 versionslast 2 versionslast 2 versionslast 2 versions

Releases

Packages

Used by

Contributors

Languages