Use Http Versions Save

🐢 React hook for making isomorphic http requests

1.0.8

4 years ago
  1. this removes the path and url fields in exchange for the 1st argument handling both. https://github.com/ava/use-http/issues/247 🚨 BREAKING 🚨
useFetch('/path')
// AND
useFetch('https://overwrite-global-url.com')
  1. Fixes issue when overwriting global options, it changes for every instance of useFetch. https://github.com/ava/use-http/issues/250

  2. fixes the pagination issue here https://github.com/ava/use-http/issues/237 but might not fix the loading bug.

  3. small bug fix with responseType

1.0.6

4 years ago

Scalable Interceptor Arguments

🚨🚨THIS RELEASE CONTAINS BREAKING CHANGES!!! 🚨🚨 Due potential future scalability issues such as adding new items to pass to the interceptors, we're changing it to an object destructuring syntax instead of multiple arguments.

useFetch({
  interceptors: {
    request: async (options, url, path, route) => {},
    response: async (response) => {}
  }
}

will now be

useFetch({
  interceptors: {
    request: async ({ options, url, path, route }) => {}, // <- notice object destructuring
    response: async ({ response }) => {} // <- notice object destructuring
  }
}

This provides a few benefits.

  1. we can now add new options to these callbacks without having breaking changes
  2. we can pull out these options in whatever order so we don't have unused variables

For example, let's say in the future we want to do

useFetch({
  interceptors: {
    request: async ({ options, route, attempt }) => {
      // now we can add a new field `attempt`
      // and we can just grab `route` without `url` and `path`
    },
    response: async ({ response, attempt }) => {
      // now we can add a new field `attempt`
    }
  }
}

responseType option

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. Defaults to: ['json', 'text', 'blob', 'readableStream']

useFetch({
  // this would basically call `await response.json()`
  // and set the `data` and `response.data` field to the output
  responseType: 'json',
  // OR can be an array. It's an array by default.
  // We will try to get the `data` by attempting to extract
  // it via these body interface methods, one by one in
  // this order. We skip `formData` because it's mostly used
  // for service workers.
  responseType: ['json', 'text', 'blob', 'arrayBuffer'],
})

1.0.2

4 years ago

Finally Version 1.0

Lots of upgrades in this version. This new major release is v1.0.2 on npm.

Updates

  1. Retry Functionality. retries, retryDelay, and retryOn
  2. Suspense(experimental) Support. suspense
  3. Persistent Caching. persist
  4. Added cache to return of useFetch for better cache debugging and to clear the cache for instance when a user signs out.
  5. Fixed infinite loop/extra rendering issues when passing useFetch variables to useEffect dependencies https://github.com/ava/use-http/issues/228 https://github.com/ava/use-http/issues/185
  6. Fixed response interceptor not firing when results loaded from cache https://github.com/ava/use-http/issues/235
  7. Can now have [] and '' as body of http request. Caveat, if posting a string as the body, must have a route post('/', 'your body')
  8. Added async support for interceptors.response https://github.com/ava/use-http/issues/214
  9. Remove content-type: application/json when posting formData https://github.com/ava/use-http/issues/213
  10. Promise.all fixes https://github.com/ava/use-http/issues/211
  11. Fixed cannot perform update on unmounted component bug https://github.com/ava/use-http/issues/207
  12. Should now work in TypeScript apps made using parcel https://github.com/ava/use-http/issues/202
  13. Lot's of videos added!

0.2.1

4 years ago

🚨⚠️ This release has breaking changes! ⚠️🚨

  • removed onMount and onUpdate in exchange for accepting a dependency array as the last argument of useFetch
  • added onNewData to be used for merging new fetched data with current data for pagination

onMount AND onUpdate Pagination example

import useFetch, { Provider } from 'use-http'

const Todos = () => {
  const [page, setPage] = useState(1)

  const { data, loading } = useFetch({
    path: `/todos?page=${page}&amountPerPage=15`,
    onNewData: (currTodos, newTodos) => [...currTodos, ...newTodos], // appends newly fetched todos
    data: []
  }, [page]) // runs onMount AND whenever the `page` updates (onUpdate)

  return (
    <ul>
      {data.map(todo => <li key={todo.id}>{todo.title}</li>}
      {loading && 'Loading...'}
      {!loading && (
        <button onClick={() => setPage(page + 1)}>Load More Todos</button>
      )}
    </ul>
  )
}

const App = () => (
  <Provider url='https://example.com'>
    <Todos />
  </Provider>
)

onMount only example

import useFetch, { Provider } from 'use-http'

function Todos() {
  const { loading, error, data } = useFetch({
    path: '/todos',
    data: []
  }, []) // onMount

  return (
    <>
      {error && 'Error!'}
      {loading && 'Loading...'}
      {data.map(todo => (
        <div key={todo.id}>{todo.title}</div>
      )}
    </>
  )
}

const App = () => (
  <Provider url='https://example.com'>
    <Todos />
  </Provider>
)

onUpdate only example:

If for some reason you need to only do onUpdate without onMount, you will have to use managed state for this.

import useFetch, { Provider } from 'use-http'

function Todos() {
  const { loading, error, get, data } = useFetch({
    path: '/todos',
    data: []
  })

  const mounted = useRef(false)
  useEffect(() => {
    if (mounted.current) {
      // onUpdate only
      get()
    }
    mounted.current = true
  })

  return (
    <>
      {error && 'Error!'}
      {loading && 'Loading...'}
      {data.map(todo => (
        <div key={todo.id}>{todo.title}</div>
      )}
    </>
  )
}

const App = () => (
  <Provider url='https://example.com'>
    <Todos />
  </Provider>
)

1.2

4 years ago

Provider, useMutation, and useQuery

Provider using the GraphQL useMutation and useQuery

The Provider allows us to set a default url, options (such as headers) and so on. There is array and object destructuring for useMutation and useQuery.

Query for todos

import { Provider, useQuery, useMutation } from 'use-http'

function QueryComponent() {
  const request = useQuery(`
    query Todos($userID string!) {
      todos(userID: $userID) {
        id
        title
      }
    }
  `)

  const getTodosForUser = id => request.query({ userID: id })
  
  return (
    <>
      <button onClick={() => getTodosForUser('theUsersID')}>Get User's Todos</button>
      {request.loading ? 'Loading...' : <pre>{request.data}</pre>}
    </>
  )
}

Add a new todo

This uses array destructuring, but it can also use object destructuring. The useMutation and useQuery are very similar to the usePost's array and object destructuring.

function MutationComponent() {
  const [todoTitle, setTodoTitle] = useState('')
  
  const [data, loading, error, mutate] = useMutation(`
    mutation CreateTodo($todoTitle string) {
      todo(title: $todoTitle) {
        id
        title
      }
    }
  `)
  
  const createtodo = () => mutate({ todoTitle })

  return (
    <>
      <input onChange={e => setTodoTitle(e.target.value)} />
      <button onClick={createTodo}>Create Todo</button>
      {loading ? 'Loading...' : <pre>{data}</pre>}
    </>
  )
}

Fetch more todos

function FetchComponent() {
  const request = useFetch('/todos')
  
  return (
    <>
      <button onClick={request.get}>Get Todos</button>
      {request.loading ? 'Loading...' : <pre>{request.data}</pre>}
    </>
  )
}

Provider

These props are defaults used in every request inside the <Provider />. They can be overwritten individually

function App() {

  const options = {
    headers: {
      Authorization: 'Bearer:asdfasdfasdfasdfasdafd'
    }
  }
  
  return (
    <Provider url='http://example.com' options={options}>
      <QueryComponent />
      <MutationComponent />
      <FetchComponent />
    <Provider/>
  )
}

1.1

5 years ago

Abort

In this release, we've added abort functionality. Now you can call abort on any http request and it will cancel it. We decided not to allow aborting multiple requests at once. If the community decides that this is a feature we need to add, we will add it. If you want that, please comment on the Feature request and syntax ideas issue.

const githubRepos = useFetch({
  baseUrl: `https://api.github.com/search/repositories?q=`
})

// the line below is not isomorphic, but for simplicity we're using the browsers `encodeURI`
const searchGithubRepos = e => githubRepos.get(encodeURI(e.target.value))

<>
  <input onChange={searchGithubRepos} />
  <button onClick={githubRepos.abort}>Abort</button>
  {githubRepos.loading ? 'Loading...' : githubRepos.data.items.map(repo => (
    <div key={repo.id}>{repo.name}</div>
  ))}
</>

1.0

5 years ago

Changing the original behavior from only fetching on mount to whenever you want. Previous behavior:

import useFetch from 'use-http'

function App() {
  // add whatever other options you would add to `fetch` such as headers
  const options = {
    method: 'POST',
    body: {}, // whatever data you want to send
  }
  
  var [data, loading, error] = useFetch('https://example.com', options)
  
  // want to use object destructuring? You can do that too
  var { data, loading, error } = useFetch('https://example.com', options)
  
  if (error) return 'Error!'
  if (loading) return 'Loading!'
  
  return (
    <code>
      <pre>{data}</pre>
    </code>
  )
}

this would only work when the component first rendered. Now we can do

import useFetch from 'use-http'

function App() {
  // add whatever other options you would add to `fetch` such as headers
  const options = {}
  
  var [data, loading, error, request] = useFetch('https://example.com', options)
  
  // want to use object destructuring? You can do that too
  var { data, loading, error, request, get, post, patch, put, del } = useFetch('https://example.com')
  
  const postData = () => {
    post({
      no: 'way',
    })
    // OR
   request.post({
      no: 'way',
    })
  }

  if (error) return 'Error!'
  if (loading) return 'Loading!'
  
  return (
    <>
      <button onClick={postData}>Post Some Data</button>
      <code>
        <pre>{data}</pre>
      </code>
    </>
  )
}

There's also support for

var [data, loading, error, request] = useFetch({
  onMount: true, // will fire on componentDidMount
  baseUrl: 'https://example.com'
})

const handleClick = () => {
  request.post('/todos', {
    id: 'someID',
    text: 'this is what my todo is'
  })
}

And don't forget

var { data, loading, error, patch } = usePatch({
  url: 'https://example.com',
  headers: {
    'Content-type': 'application/json; charset=UTF-8'
  }
})