Installations
npm install use-http
Developer Guide
Typescript
No
Module System
CommonJS
Score
89.7
Supply Chain
91.4
Quality
75.6
Maintenance
100
Vulnerability
100
License
Releases
Removal of "path" and "url" fields
Published on 23 Apr 2020
Scalable Interceptor Arguments, responseType option
Published on 17 Apr 2020
Version 1.0
Published on 14 Apr 2020
Pagination + Moving to dependency array for onMount + onUpdate
Published on 19 Nov 2019
Support for a Provider, useMutation, and useQuery
Published on 20 Jun 2019
Abort Functionality
Published on 28 Apr 2019
Contributors
Unable to fetch Contributors
Languages
TypeScript (99.13%)
JavaScript (0.87%)
Developer
Download Statistics
Total Downloads
4,960,892
Last Day
3,725
Last Week
17,442
Last Month
75,600
Last Year
1,119,251
GitHub Statistics
2,313 Stars
714 Commits
114 Forks
18 Watching
18 Branches
36 Contributors
Bundle Size
27.94 kB
Minified
7.60 kB
Minified + Gzipped
Package Meta Information
Latest Version
1.0.28
Package Id
use-http@1.0.28
Unpacked Size
219.15 kB
Size
47.33 kB
File Count
69
Publised On
04 May 2023
Total Downloads
Cumulative downloads
Total Downloads
4,960,892
Last day
-17.9%
3,725
Compared to previous day
Last week
-11.2%
17,442
Compared to previous week
Last month
-0.6%
75,600
Compared to previous month
Last year
-8.1%
1,119,251
Compared to previous year
Daily Downloads
Weekly Downloads
Monthly Downloads
Yearly Downloads
Dependencies
3
Dev Dependencies
33
useFetch
Main Documentation
npm i use-http
Features
- SSR (server side rendering) support
- TypeScript support
- 2 dependencies (use-ssr, urs)
- GraphQL support (queries + mutations)
- Provider to set default
url
andoptions
- Request/response interceptors
- React Native support
- Aborts/Cancels pending http requests when a component unmounts
- Built in caching
- Persistent caching support
- Suspense(experimental) support
- Retry functionality
Usage
Examples + Videos
- useFetch - managed state, request, response, etc.
- useFetch - request/response interceptors
- useFetch - retries, retryOn, retryDelay
- useFetch - abort, timeout, onAbort, onTimeout
- useFetch - persist, cache
- useFetch - cacheLife, cachePolicy
- useFetch - suspense (experimental)
- useFetch - pagination
- useQuery - GraphQL
- useFetch - Next.js
- useFetch - create-react-app
Basic Usage Managed State useFetch
If the last argument of useFetch
is not a dependency array []
, then it will not fire until you call one of the http methods like get
, post
, etc.
1import useFetch from 'use-http' 2 3function Todos() { 4 const [todos, setTodos] = useState([]) 5 const { get, post, response, loading, error } = useFetch('https://example.com') 6 7 useEffect(() => { initializeTodos() }, []) // componentDidMount 8 9 async function initializeTodos() { 10 const initialTodos = await get('/todos') 11 if (response.ok) setTodos(initialTodos) 12 } 13 14 async function addTodo() { 15 const newTodo = await post('/todos', { title: 'my new todo' }) 16 if (response.ok) setTodos([...todos, newTodo]) 17 } 18 19 return ( 20 <> 21 <button onClick={addTodo}>Add Todo</button> 22 {error && 'Error!'} 23 {loading && 'Loading...'} 24 {todos.map(todo => ( 25 <div key={todo.id}>{todo.title}</div> 26 ))} 27 </> 28 ) 29}
Basic Usage Auto-Managed State useFetch
This fetch is run onMount/componentDidMount
. The last argument []
means it will run onMount
. If you pass it a variable like [someVariable]
, it will run onMount
and again whenever someVariable
changes values (aka onUpdate
). If no method is specified, GET is the default.
1import useFetch from 'use-http' 2 3function Todos() { 4 const options = {} // these options accept all native `fetch` options 5 // the last argument below [] means it will fire onMount (GET by default) 6 const { loading, error, data = [] } = useFetch('https://example.com/todos', options, []) 7 return ( 8 <> 9 {error && 'Error!'} 10 {loading && 'Loading...'} 11 {data.map(todo => ( 12 <div key={todo.id}>{todo.title}</div> 13 ))} 14 </> 15 ) 16}
Suspense Mode(experimental) Auto-Managed State
Can put suspense
in 2 places. Either useFetch
(A) or Provider
(B).
1import useFetch, { Provider } from 'use-http' 2 3function Todos() { 4 const { data: todos = [] } = useFetch('/todos', { 5 suspense: true // A. can put `suspense: true` here 6 }, []) // onMount 7 8 return todos.map(todo => <div key={todo.id}>{todo.title}</div>) 9} 10 11function App() { 12 const options = { 13 suspense: true // B. can put `suspense: true` here too 14 } 15 return ( 16 <Provider url='https://example.com' options={options}> 17 <Suspense fallback='Loading...'> 18 <Todos /> 19 </Suspense> 20 </Provider> 21 ) 22}
Suspense Mode(experimental) Managed State
Can put suspense
in 2 places. Either useFetch
(A) or Provider
(B). Suspense mode via managed state is very experimental.
1import useFetch, { Provider } from 'use-http' 2 3function Todos() { 4 const [todos, setTodos] = useState([]) 5 // A. can put `suspense: true` here 6 const { get, response } = useFetch({ suspense: true }) 7 8 const loadInitialTodos = async () => { 9 const todos = await get('/todos') 10 if (response.ok) setTodos(todos) 11 } 12 13 // componentDidMount 14 useEffect(() => { 15 loadInitialTodos() 16 }, []) 17 18 return todos.map(todo => <div key={todo.id}>{todo.title}</div>) 19} 20 21function App() { 22 const options = { 23 suspense: true // B. can put `suspense: true` here too 24 } 25 return ( 26 <Provider url='https://example.com' options={options}> 27 <Suspense fallback='Loading...'> 28 <Todos /> 29 </Suspense> 30 </Provider> 31 ) 32}
Consider sponsoring
Ava, Rapid Application Development
Need a freelance software engineer with more than 5 years production experience at companies like Facebook, Discord, Best Buy, and Citrix?
website | email | twitter
Pagination + Provider
The onNewData
will take the current data, and the newly fetched data, and allow you to merge the two however you choose. In the example below, we are appending the new todos to the end of the current todos.
1import useFetch, { Provider } from 'use-http' 2 3const Todos = () => { 4 const [page, setPage] = useState(1) 5 6 const { data = [], loading } = useFetch(`/todos?page=${page}&amountPerPage=15`, { 7 onNewData: (currTodos, newTodos) => [...currTodos, ...newTodos], // appends newly fetched todos 8 perPage: 15, // stops making more requests if last todos fetched < 15 9 }, [page]) // runs onMount AND whenever the `page` updates (onUpdate) 10 11 return ( 12 <ul> 13 {data.map(todo => <li key={todo.id}>{todo.title}</li>} 14 {loading && 'Loading...'} 15 {!loading && ( 16 <button onClick={() => setPage(page + 1)}>Load More Todos</button> 17 )} 18 </ul> 19 ) 20} 21 22const App = () => ( 23 <Provider url='https://example.com'> 24 <Todos /> 25 </Provider> 26)
Destructured useFetch
⚠️ Do not destructure the response
object! Details in this video. Technically you can do it, but if you need to access the response.ok
from, for example, within a component's onClick handler, it will be a stale value for ok
where it will be correct for response.ok
. ️️⚠️
1var [request, response, loading, error] = useFetch('https://example.com') 2 3// want to use object destructuring? You can do that too 4var { 5 request, 6 response, // 🚨 Do not destructure the `response` object! 7 loading, 8 error, 9 data, 10 cache, // methods: get, set, has, delete, clear (like `new Map()`) 11 get, 12 post, 13 put, 14 patch, 15 delete // don't destructure `delete` though, it's a keyword 16 del, // <- that's why we have this (del). or use `request.delete` 17 head, 18 options, 19 connect, 20 trace, 21 mutate, // GraphQL 22 query, // GraphQL 23 abort 24} = useFetch('https://example.com') 25 26// 🚨 Do not destructure the `response` object! 27// 🚨 This just shows what fields are available in it. 28var { 29 ok, 30 status, 31 headers, 32 data, 33 type, 34 statusText, 35 url, 36 body, 37 bodyUsed, 38 redirected, 39 // methods 40 json, 41 text, 42 formData, 43 blob, 44 arrayBuffer, 45 clone 46} = response 47 48var { 49 loading, 50 error, 51 data, 52 cache, // methods: get, set, has, delete, clear (like `new Map()`) 53 get, 54 post, 55 put, 56 patch, 57 delete // don't destructure `delete` though, it's a keyword 58 del, // <- that's why we have this (del). or use `request.delete` 59 mutate, // GraphQL 60 query, // GraphQL 61 abort 62} = request
Relative routes useFetch
1var request = useFetch('https://example.com') 2 3request.post('/todos', { 4 no: 'way' 5})
Abort useFetch
1const { get, abort, loading, data: repos } = useFetch('https://api.github.com/search/repositories?q=') 2 3// the line below is not isomorphic, but for simplicity we're using the browsers `encodeURI` 4const searchGithubRepos = e => get(encodeURI(e.target.value)) 5 6<> 7 <input onChange={searchGithubRepos} /> 8 <button onClick={abort}>Abort</button> 9 {loading ? 'Loading...' : repos.data.items.map(repo => ( 10 <div key={repo.id}>{repo.name}</div> 11 ))} 12</>
GraphQL Query useFetch
1 2const QUERY = ` 3 query Todos($userID string!) { 4 todos(userID: $userID) { 5 id 6 title 7 } 8 } 9` 10 11function App() { 12 const request = useFetch('http://example.com') 13 14 const getTodosForUser = id => request.query(QUERY, { userID: id }) 15 16 return ( 17 <> 18 <button onClick={() => getTodosForUser('theUsersID')}>Get User's Todos</button> 19 {request.loading ? 'Loading...' : <pre>{request.data}</pre>} 20 </> 21 ) 22}
GraphQL Mutation useFetch
The Provider
allows us to set a default url
, options
(such as headers) and so on.
1 2const MUTATION = ` 3 mutation CreateTodo($todoTitle string) { 4 todo(title: $todoTitle) { 5 id 6 title 7 } 8 } 9` 10 11function App() { 12 const [todoTitle, setTodoTitle] = useState('') 13 const request = useFetch('http://example.com') 14 15 const createtodo = () => request.mutate(MUTATION, { todoTitle }) 16 17 return ( 18 <> 19 <input onChange={e => setTodoTitle(e.target.value)} /> 20 <button onClick={createTodo}>Create Todo</button> 21 {request.loading ? 'Loading...' : <pre>{request.data}</pre>} 22 </> 23 ) 24}
Provider
using the GraphQL useMutation
and useQuery
Query for todos
1import { useQuery } from 'use-http' 2 3export default function QueryComponent() { 4 5 // can also do it this way: 6 // const [data, loading, error, query] = useQuery` 7 // or this way: 8 // const { data, loading, error, query } = useQuery` 9 const request = useQuery` 10 query Todos($userID string!) { 11 todos(userID: $userID) { 12 id 13 title 14 } 15 } 16 ` 17 18 const getTodosForUser = id => request.query({ userID: id }) 19 20 return ( 21 <> 22 <button onClick={() => getTodosForUser('theUsersID')}>Get User's Todos</button> 23 {request.loading ? 'Loading...' : <pre>{request.data}</pre>} 24 </> 25 ) 26}
Add a new todo
1import { useMutation } from 'use-http' 2 3export default function MutationComponent() { 4 const [todoTitle, setTodoTitle] = useState('') 5 6 // can also do it this way: 7 // const request = useMutation` 8 // or this way: 9 // const { data, loading, error, mutate } = useMutation` 10 const [data, loading, error, mutate] = useMutation` 11 mutation CreateTodo($todoTitle string) { 12 todo(title: $todoTitle) { 13 id 14 title 15 } 16 } 17 ` 18 19 const createTodo = () => mutate({ todoTitle }) 20 21 return ( 22 <> 23 <input onChange={e => setTodoTitle(e.target.value)} /> 24 <button onClick={createTodo}>Create Todo</button> 25 {loading ? 'Loading...' : <pre>{data}</pre>} 26 </> 27 ) 28}
Adding the Provider
These props are defaults used in every request inside the <Provider />
. They can be overwritten individually
1import { Provider } from 'use-http' 2import QueryComponent from './QueryComponent' 3import MutationComponent from './MutationComponent' 4 5function App() { 6 7 const options = { 8 headers: { 9 Authorization: 'Bearer YOUR_TOKEN_HERE' 10 } 11 } 12 13 return ( 14 <Provider url='http://example.com' options={options}> 15 <QueryComponent /> 16 <MutationComponent /> 17 <Provider/> 18 ) 19} 20
Request/Response Interceptors
This example shows how we can do authentication in the request
interceptor and how we can camelCase the results in the response
interceptor
1import { Provider } from 'use-http' 2import { toCamel } from 'convert-keys' 3 4function App() { 5 let [token, setToken] = useLocalStorage('token') 6 7 const options = { 8 interceptors: { 9 // every time we make an http request, this will run 1st before the request is made 10 // url, path and route are supplied to the interceptor 11 // request options can be modified and must be returned 12 request: async ({ options, url, path, route }) => { 13 if (isExpired(token)) { 14 token = await getNewToken() 15 setToken(token) 16 } 17 options.headers.Authorization = `Bearer ${token}` 18 return options 19 }, 20 // every time we make an http request, before getting the response back, this will run 21 response: async ({ response, request }) => { 22 // unfortunately, because this is a JS Response object, we have to modify it directly. 23 // It shouldn't have any negative affect since this is getting reset on each request. 24 const res = response 25 if (res.data) res.data = toCamel(res.data) 26 return res 27 } 28 } 29 } 30 31 return ( 32 <Provider url='http://example.com' options={options}> 33 <SomeComponent /> 34 <Provider/> 35 ) 36} 37
File Uploads (FormData)
This example shows how we can upload a file using useFetch
.
1import useFetch from 'use-http' 2 3const FileUploader = () => { 4 const [file, setFile] = useState() 5 6 const { post } = useFetch('https://example.com/upload') 7 8 const uploadFile = async () => { 9 const data = new FormData() 10 data.append('file', file) 11 if (file instanceof FormData) await post(data) 12 } 13 14 return ( 15 <div> 16 {/* Drop a file onto the input below */} 17 <input onChange={e => setFile(e.target.files[0])} /> 18 <button onClick={uploadFile}>Upload</button> 19 </div> 20 ) 21}
Handling Different Response Types
This example shows how we can get .json()
, .text()
, .formData()
, .blob()
, .arrayBuffer()
, and all the other http response methods. By default, useFetch
1st tries to call response.json()
under the hood, if that fails it's backup is response.text()
. If that fails, then you need a different response type which is where this comes in.
1import useFetch from 'use-http' 2 3const App = () => { 4 const [name, setName] = useState('') 5 6 const { get, loading, error, response } = useFetch('http://example.com') 7 8 const handleClick = async () => { 9 await get('/users/1?name=true') // will return just the user's name 10 const text = await response.text() 11 setName(text) 12 } 13 14 return ( 15 <> 16 <button onClick={handleClick}>Load Data</button> 17 {error && error.messge} 18 {loading && "Loading..."} 19 {name && <div>{name}</div>} 20 </> 21 ) 22}
Overwrite/Remove Options/Headers Set in Provider
This example shows how to remove a header all together. Let's say you have <Provider url='url.com' options={{ headers: { Authentication: 'Bearer MY_TOKEN' } }}><App /></Provider>
, but for one api call, you don't want that header in your useFetch
at all for one instance in your app. This would allow you to remove that.
1import useFetch from 'use-http' 2 3const Todos = () => { 4 // let's say for this request, you don't want the `Accept` header at all 5 const { loading, error, data: todos = [] } = useFetch('/todos', globalOptions => { 6 delete globalOptions.headers.Accept 7 return globalOptions 8 }, []) // onMount 9 return ( 10 <> 11 {error && error.messge} 12 {loading && "Loading..."} 13 {todos && <ul>{todos.map(todo => <li key={todo.id}>{todo.title}</li>)}</ul>} 14 </> 15 ) 16} 17 18const App = () => { 19 const options = { 20 headers: { 21 Accept: 'application/json' 22 } 23 } 24 return ( 25 <Provider url='https://url.com' options={options}><Todos /></Provider> 26}
Retries retryOn & retryDelay
In this example you can see how retryOn
will retry on a status code of 305
, or if we choose the retryOn()
function, it returns a boolean to decide if we will retry. With retryDelay
we can either have a fixed delay, or a dynamic one by using retryDelay()
. Make sure retries
is set to at minimum 1
otherwise it won't retry the request. If retries > 0
without retryOn
then by default we always retry if there's an error or if !response.ok
. If retryOn: [400]
and retries > 0
then we only retry on a response status of 400
.
1import useFetch from 'use-http'
2
3const TestRetry = () => {
4 const { response, get } = useFetch('https://httpbin.org/status/305', {
5 // make sure `retries` is set otherwise it won't retry
6 retries: 1,
7 retryOn: [305],
8 // OR
9 retryOn: async ({ attempt, error, response }) => {
10 // returns true or false to determine whether to retry
11 return error || response && response.status >= 300
12 },
13
14 retryDelay: 3000,
15 // OR
16 retryDelay: ({ attempt, error, response }) => {
17 // exponential backoff
18 return Math.min(attempt > 1 ? 2 ** attempt * 1000 : 1000, 30 * 1000)
19 // linear backoff
20 return attempt * 1000
21 }
22 })
23
24 return (
25 <>
26 <button onClick={() => get()}>CLICK</button>
27 <pre>{JSON.stringify(response, null, 2)}</pre>
28 </>
29 )
30}
Overview
Hooks
Hook | Description |
---|---|
useFetch | The base hook |
useQuery | For making a GraphQL query |
useMutation | For making a GraphQL mutation |
Options
This is exactly what you would pass to the normal js fetch
, with a little extra. All these options can be passed to the <Provider options={/* every option below */} />
, or directly to useFetch
. If you have both in the <Provider />
and in useFetch
, the useFetch
options will overwrite the ones from the <Provider />
Option | Description | Default |
---|---|---|
cacheLife | After a successful cache update, that cache data will become stale after this duration | 0 |
cachePolicy | These will be the same ones as Apollo's fetch policies. Possible values are cache-and-network , network-only , cache-only , no-cache , cache-first . Currently only supports cache-first or no-cache | cache-first |
data | Allows you to set a default value for data | undefined |
interceptors.request | Allows you to do something before an http request is sent out. Useful for authentication if you need to refresh tokens a lot. | undefined |
interceptors.response | Allows you to do something after an http response is recieved. Useful for something like camelCasing the keys of the response. | undefined |
loading | Allows you to set default value for loading | false unless the last argument of useFetch is [] |
onAbort | Runs when the request is aborted. | empty function |
onError | Runs when the request get's an error. If retrying, it is only called on the last retry attempt. | empty function |
onNewData | Merges the current data with the incoming data. Great for pagination. | (curr, new) => new |
onTimeout | Called when the request times out. | empty function |
persist | Persists data for the duration of cacheLife . If cacheLife is not set it defaults to 24h. Currently only available in Browser. | false |
perPage | Stops making more requests if there is no more data to fetch. (i.e. if we have 25 todos, and the perPage is 10, after fetching 2 times, we will have 20 todos. The last 5 tells us we don't have any more to fetch because it's less than 10) For pagination. | 0 |
responseType | This will determine how the data field is set. If you put json then it will try to parse it as JSON. If you set it as an array, it will attempt to parse the response in the order of the types you put in the array. Read about why we don't put formData in the defaults in the yellow Note part here. | ['json', 'text', 'blob', 'readableStream'] |
retries | When a request fails or times out, retry the request this many times. By default it will not retry. | 0 |
retryDelay | You can retry with certain intervals i.e. 30 seconds 30000 or with custom logic (i.e. to increase retry intervals). | 1000 |
retryOn | You can retry on certain http status codes or have custom logic to decide whether to retry or not via a function. Make sure retries > 0 otherwise it won't retry. | [] |
suspense | Enables Experimental React Suspense mode. example | false |
timeout | The request will be aborted/cancelled after this amount of time. This is also the interval at which retries will be made at. in milliseconds. If set to 0 , it will not timeout except for browser defaults. | 0 |
1const options = { 2 // accepts all `fetch` options such as headers, method, etc. 3 4 // The time in milliseconds that cache data remains fresh. 5 cacheLife: 0, 6 7 // Cache responses to improve speed and reduce amount of requests 8 // Only one request to the same endpoint will be initiated unless cacheLife expires for 'cache-first'. 9 cachePolicy: 'cache-first', // 'no-cache' 10 11 // set's the default for the `data` field 12 data: [], 13 14 // typically, `interceptors` would be added as an option to the `<Provider />` 15 interceptors: { 16 request: async ({ options, url, path, route }) => { // `async` is not required 17 return options // returning the `options` is important 18 }, 19 response: async ({ response, request }) => { 20 // notes: 21 // - `response.data` is equivalent to `await response.json()` 22 // - `request` is an object matching the standard fetch's options 23 return response // returning the `response` is important 24 } 25 }, 26 27 // set's the default for `loading` field 28 loading: false, 29 30 // called when aborting the request 31 onAbort: () => {}, 32 33 // runs when an error happens. 34 onError: ({ error }) => {}, 35 36 // this will allow you to merge the `data` for pagination. 37 onNewData: (currData, newData) => { 38 return [...currData, ...newData] 39 }, 40 41 // called when the request times out 42 onTimeout: () => {}, 43 44 // this will tell useFetch not to run the request if the list doesn't haveMore. (pagination) 45 // i.e. if the last page fetched was < 15, don't run the request again 46 perPage: 15, 47 48 // Allows caching to persist after page refresh. Only supported in the Browser currently. 49 persist: false, 50 51 // this would basically call `await response.json()` 52 // and set the `data` and `response.data` field to the output 53 responseType: 'json', 54 // OR can be an array. It's an array by default. 55 // We will try to get the `data` by attempting to extract 56 // it via these body interface methods, one by one in 57 // this order. We skip `formData` because it's mostly used 58 // for service workers. 59 responseType: ['json', 'text', 'blob', 'arrayBuffer'], 60 61 // amount of times it should retry before erroring out 62 retries: 3, 63 64 // The time between retries 65 retryDelay: 10000, 66 // OR 67 // Can be a function which is used if we want change the time in between each retry 68 retryDelay({ attempt, error, response }) { 69 // exponential backoff 70 return Math.min(attempt > 1 ? 2 ** attempt * 1000 : 1000, 30 * 1000) 71 // linear backoff 72 return attempt * 1000 73 }, 74 75 // make sure `retries` is set otherwise it won't retry 76 // can retry on certain http status codes 77 retryOn: [503], 78 // OR 79 async retryOn({ attempt, error, response }) { 80 // retry on any network error, or 4xx or 5xx status codes 81 if (error !== null || response.status >= 400) { 82 console.log(`retrying, attempt number ${attempt + 1}`); 83 return true; 84 } 85 }, 86 87 // enables experimental React Suspense mode 88 suspense: true, // defaults to `false` 89 90 // amount of time before the request get's canceled/aborted 91 timeout: 10000, 92} 93 94useFetch(options) 95// OR 96<Provider options={options}><ResOfYourApp /></Provider>
Who's using use-http?
Does your company use use-http? Consider sponsoring the project to fund new features, bug fixes, and more.
Browser Support
If you need support for IE, you will need to add additional polyfills. The React docs suggest these polyfills, but from this issue we have found it to work fine with the react-app-polyfill
. If you have any updates to this browser list, please submit a PR!
Edge | Firefox | Chrome | Safari | Opera |
---|---|---|---|---|
12+ | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
Feature Requests/Ideas
If you have feature requests, submit an issue to let us know what you would like to see!
Todos
-
prefetching
-
global cache state management
-
optimistic updates
-
persist
support for React Native -
better loading state management. When using only 1 useFetch in a component and we use
Promise.all([get('/todos/1'), get('/todos/2')])
then don't have a loading true, loading false on each request. Just have loading true on 1st request, and loading false on last request. -
is making a gitpod useful here? 🤔
-
suspense
- triggering it from outside the
<Suspense />
component.- add
.read()
torequest
- or make it work with just the
suspense: true
option - both of these options need to be thought out a lot more^
- add
- tests for this^ (triggering outside)
- cleanup tests in general. Snapshot tests are unpredictably not working for some reason.
- snapshot test resources: swr, react-apollo-hooks
- basic test resources: fetch-suspense, @testing-library/react-hooks suspense PR
- triggering it from outside the
-
maybe add translations like this one
-
maybe add contributors all-contributors
-
add sponsors similar to this
-
Error handling
- if calling
response.json()
and there is no response yet
- if calling
-
tests
- tests for SSR
- tests for react native see here
- tests for GraphQL hooks
useMutation
+useQuery
- tests for stale
response
see this PR - tests to make sure
response.formData()
and some of the other httpresponse methods
work properly - the
onMount
works properly with all variants of passinguseEffect(fn, [request.get])
and not causing an infinite loop -
async
tests forinterceptors.response
- aborts fetch on unmount
- does not abort fetch on every rerender
-
retryDelay
andtimeout
are both set. It works, but is annoying to deal with timers in tests. resource -
timeout
withretries > 0
. (also doretires > 1
) Need to figure out how to advance timers properly to write this and the test above
-
take a look at how react-apollo-hooks work. Maybe ad
useSubscription
andconst request = useFetch(); request.subscribe()
or something along those lines -
make this a github package
-
Documentation:
- show comparison with Apollo
- figure out a good way to show side-by-side comparisons
- show comparison with Axios
-
potential option ideas
1const request = useFetch({ 2 graphql: { 3 // all options can also be put in here 4 // to overwrite those of `useFetch` for 5 // `useMutation` and `useQuery` 6 }, 7 // by default this is true, but if set to false 8 // then we default to the responseType array of trying 'json' first, then 'text', etc. 9 // hopefully I get some answers on here: https://bit.ly/3afPlJS 10 responseTypeGuessing: true, 11 12 // Allows you to pass in your own cache to useFetch 13 // This is controversial though because `cache` is an option in the requestInit 14 // and it's value is a string. See: https://developer.mozilla.org/en-US/docs/Web/API/Request/cache 15 // One possible solution is to move the default `fetch`'s `cache` to `cachePolicy`. 16 // I don't really like this solution though. 17 // Another solution is to only allow the `cache` option with the `<Provider cache={new Map()} />` 18 cache: new Map(), 19 // these will be the exact same ones as Apollo's 20 cachePolicy: 'cache-and-network', 'network-only', 'cache-only', 'no-cache' // 'cache-first' 21 // potential idea to fetch on server instead of just having `loading` state. Not sure if this is a good idea though 22 onServer: true, 23 onSuccess: (/* idk what to put here */) => {}, 24 // if you would prefer to pass the query in the config 25 query: `some graphql query` 26 // if you would prefer to pass the mutation in the config 27 mutation: `some graphql mutation` 28 refreshWhenHidden: false, 29}) 30 31 32// potential for causing a rerender after clearing cache if needed 33request.cache.clear(true)
-
potential option ideas for
GraphQL
1const request = useQuery({ onMount: true })`your graphql query` 2 3const request = useFetch(...) 4const userID = 'some-user-uuid' 5const res = await request.query({ userID })` 6 query Todos($userID string!) { 7 todos(userID: $userID) { 8 id 9 title 10 } 11 } 12`
-
make code editor plugin/package/extension that adds GraphQL syntax highlighting for
useQuery
anduseMutation
😊 -
add React Native test suite
No vulnerabilities found.
Reason
no binaries found in the repo
Reason
license file detected
Details
- Info: project has a license file: license.md:0
- Info: FSF or OSI recognized license: MIT License: license.md:0
Reason
Found 12/30 approved changesets -- score normalized to 4
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
- Warn: no security policy file detected
- Warn: no security file to analyze
- Warn: no security file to analyze
- Warn: no security file to analyze
Reason
project is not fuzzed
Details
- Warn: no fuzzer integrations found
Reason
branch protection not enabled on development/release branches
Details
- Warn: branch protection not enabled for branch 'master'
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
- Warn: 0 commits out of 12 are checked with a SAST tool
Reason
32 existing vulnerabilities detected
Details
- Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92
- Warn: Project is vulnerable to: GHSA-v88g-cgmw-v5xw
- Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw
- Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg
- Warn: Project is vulnerable to: GHSA-7gc6-qh9x-w6h8
- Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275
- Warn: Project is vulnerable to: GHSA-gxpj-cx7g-858c
- Warn: Project is vulnerable to: GHSA-w573-4hg7-7wgq
- Warn: Project is vulnerable to: GHSA-ww39-953v-wcq6
- Warn: Project is vulnerable to: GHSA-43f8-2h32-f4cj
- Warn: Project is vulnerable to: GHSA-896r-f27r-55mw
- Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h
- Warn: Project is vulnerable to: GHSA-p6mc-m468-83gw
- Warn: Project is vulnerable to: GHSA-29mw-wpgm-hmr9
- Warn: Project is vulnerable to: GHSA-35jh-r3h4-6jhm
- Warn: Project is vulnerable to: GHSA-7wpw-2hjm-89gp
- Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv
- Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3
- Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h
- Warn: Project is vulnerable to: GHSA-w7rc-rwvf-8q5r
- Warn: Project is vulnerable to: GHSA-r683-j2x4-v87g
- Warn: Project is vulnerable to: GHSA-5fw9-fq32-wv5p
- Warn: Project is vulnerable to: GHSA-hj48-42vr-x3v9
- Warn: Project is vulnerable to: GHSA-hrpp-h998-j3pp
- Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6
- Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw
- Warn: Project is vulnerable to: GHSA-jgrx-mgxx-jf9v
- Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3
- Warn: Project is vulnerable to: GHSA-j8xg-fqg3-53r7
- Warn: Project is vulnerable to: GHSA-6fc8-4gx4-v693
- Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q
- Warn: Project is vulnerable to: GHSA-c4w7-xm78-47vh
Score
2.3
/10
Last Scanned on 2025-01-27
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn MoreOther packages similar to use-http
serverless-http
Use existing web application frameworks in serverless environments
npm-registry-fetch
Fetch-based http client for use with npm registry APIs
hpagent
A ready to use http and https agent for working with proxies that keeps connections alive!
@commercetools/sdk-middleware-http
Middleware for http requests, to use with @commercetools/sdk-client