Managing Fetch API requests in React.js | useConfetch
Tags: javascript, react, codenewbie, news
Published: 2020-08-25 06:14:03

Fetch + Abort Controller + timeouts + React.js

`window.fetch` is awesome, but it lacks timeouts. You can't just supply a value in milliseconds and expect the fetch request to be aborted if there is no response from the server within that time frame.
```jsx
// This timeouts after 3000s, stops listening for a response from the server.
fetch('https://your-url.com', {
  timeoutDuration: 3000
})

// THIS DOES NOT EXIST
```

Something like this would have been great! But that doesn't exist.

We as web developers have a solution for this i.e., the AbortController. Although we can't pass a timeout duration, we can pass a signal and cancel the fetch. So let's say we want to set a 1sec duration after which our fetch request aborts. This is how we would do it:
```jsx
const controller = new AbortController()
const signal = controller.signal

fetch('https://abc.xyz', { signal })

// Abort the fetch request after 1s
setTimeout(() => contoller.abort(), 1000)
```

It's perfectly fine if just want to send requests, but when you try to use something like this with a react component that shows some UI indicating the current status of the request, you can imagine the kind of mess a new developer can make. Let's say the component has a button and a text. 3 states:
- text: READY, button: clickable
- text: WAITING/LOADING, button: disabled, shows a spinner
- text: LOADING COMPLETE, button: clickable

How would you do this? Post your solutions in the comments below.
I would like to have something like:
```jsx
const { data, loading, error, send } = useSomething(fetchParameters)
```

That's right, I won't waste a second before abstracting the mess away from the component. I would also expect these values to update in realtime so that I can use them to update my component.

For those who are black-belt in REACT-FOO, and have already figured it out, it's available on npm:

## [react-confetch](https://www.npmjs.com/package/react-confetch)

I also plan on adding it as a GitHub Package soon.

If you are new to react, here are the setup steps:
- Add the package as a dependency to your project: 
```jsx
npm install --save react-confetch
```
- Wrap your app component with `ConfetchContext` like this:
```jsx
import './index.css'
 
import { ConfetchContext } from 'react-confetch'
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
 
const globalFetchConfig = {
  timeoutDuration: 3000,
}
 
ReactDOM.render((
  <ConfetchContext.Provider value={globalFetchConfig}>
    <App />
  </ConfetchContext.Provider>
), document.getElementById('root'))
```

Notice the `globalFetchConfig`? That is where you would add all the default configuration values for all fetch requests made using this package. Use the `useConfetch` hook in your components like this:
```jsx
-app.js
import React from 'react'
import { useConfetch } from 'react-confetch'
 
const App = () => {
  const convertResponseToImageData = res => res.blob().then(image => URL.createObjectURL(image))
 
  const config = {
    url: 'https://avatars.githubusercontent.com',
    endpoint: '/akshay-nm',
    body: null,
    method: 'GET',
    timeoutDuration: 10,
    onResponse: convertResponseToImageData, // this is where you add logic to handle the response, any return value will be set as data
    // onError: err => {}, // you can pass an error handler too, any return values will be assigned to error
    // any error thrown is returned as error
  }
 
  const { data, loading, error, send } = useConfetch(config)
 
  return (
    <div>
      <div>{data && <img src={data} alt='Image' />}</div>
      <div>loading: {loading? 'yes' : 'no'}</div>
      <div>error: {error? error.message: '-'}</div>
      <div>
        <button onClick={send}>Send a fetch request</button>
      </div>
    </div>
  )
}
 
export default App
```

It's just a wrapper on the whole abort functionality we talked about earlier.
I'll add some examples on how to wrap this hook for each endpoint you want to access as the component still has some extra code that can be moved elsewhere. If you are doing the same, please share some of that inspiring code!
Till next time…
# THE NAME IS REACT-CONFETCH.