dmitrykrylov / use-http

๐Ÿถ React hook for making isomorphic http requests

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

useFetch

๐Ÿถ React hook for making isomorphic http requests

undefined undefined undefined

Need to fetch some data? Try this one out. It's an isomorphic fetch hook. That means it works with SSR (server side rendering).


A note on the documentation below. Many of these examples could have performance improvements using useMemo and useCallback, but for the sake of the beginner/ease of reading, they are left out.

Examples

Installation

yarn add use-http    or    npm i -S use-http

Usage

Basic Usage

import useFetch from 'use-http'

function Todos() {
  const options = { // accepts all `fetch` options
    onMount: true // will fire on componentDidMount
  }

  const todos = useFetch('https://example.com/todos', options)

  function addTodo() {
    todos.post({
      title: 'no way',
    })
  }

  if (todos.error) return 'Error!'
  if (todos.loading) return 'Loading...'

  return (
    <>
      <button onClick={addTodo}>Add Todo</button>
      {todos.data.map(todo => (
        <div key={todo.id}>{todo.title}</div>
      )}
    </>
  )
}

Destructured

var [data, loading, error, request] = useFetch('https://example.com')

// want to use object destructuring? You can do that too
var { data, loading, error, request } = useFetch('https://example.com')

Relative routes

const request = useFetch({
  baseUrl: 'https://example.com'
})

request.post('/todos', {
  no: 'way'
})

Helper hooks

import { useGet, usePost, usePatch, usePut, useDelete } from 'use-http'

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

patch({
  yes: 'way',
})

Abort

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>
  ))}
</>

GraphQL Query

const QUERY = `
  query Todos($userID string!) {
    todos(userID: $userID) {
      id
      title
    }
  }
`

const App = () => {
  const request = useFetch('http://example.com')

  const getTodosForUser = id => request.query(QUERY, { userID: id })

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

GraphQL Mutation

const MUTATION = `
  mutation CreateTodo($todoTitle string) {
    todo(title: $todoTitle) {
      id
      title
    }
  }
`

const App = () => {
  const [todoTitle, setTodoTitle] = useState('')
  const request = useFetch('http://example.com')

  const createtodo = () => request.mutate(MUTATION, { todoTitle })

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

The Goal With Suspense (not implemented yet)

import React, { Suspense, unstable_ConcurrentMode as ConcurrentMode, useEffect } from 'react'

const WithSuspense = () => {
  const suspense = useFetch('https://example.com')

  useEffect(() => {
    suspense.read()
  }, [])

  if (!suspense.data) return null

  return <pre>{suspense.data}</pre>
}

const App = () => (
  <ConcurrentMode>
    <Suspense fallback="Loading...">
      <WithSuspense />
    </Suspense>
  </ConcurrentMode>
)

Hooks

Option Description
useFetch The base hook
useGet Defaults to a GET request
usePost Defaults to a POST request
usePut Defaults to a PUT request
usePatch Defaults to a PATCH request
useDelete Defaults to a DELETE request

Options

This is exactly what you would pass to the normal js fetch, with a little extra.

Option Description Default
onMount Once the component mounts, the http request will run immediately false
baseUrl Allows you to set a base path so relative paths can be used for each request :) empty string
const {
  data,
  loading,
  error,
  request,
  get,
  post,
  patch,
  put,
  delete  // don't destructure `delete` though, it's a keyword
  del,    // <- that's why we have this (del). or use `request.delete`
  abort,
  query,  // GraphQL
  mutate, // GraphQL
} = useFetch({
  url: 'https://example.com',
  baseUrl: 'https://example.com',
  onMount: true
})

or

const [data, loading, error, request] = useFetch({
  url: 'https://example.com',
  baseUrl: 'https://example.com',
  onMount: true
})

const {
  get,
  post,
  patch,
  put,
  delete  // don't destructure `delete` though, it's a keyword
  del,    // <- that's why we have this (del). or use `request.delete`
  abort,
  query,  // GraphQL
  mutate, // GraphQL
} = request

Credits

use-http is heavily inspired by the popular http client axios

Feature Requests/Ideas

If you have feature requests, let's talk about them in this issue!

Todos

  • Make work with React Suspense current example WIP
  • get it all working on a SSR codesandbox, this way we can have api to call locally
  • Allow option to fetch on server instead of just having loading state
  • Allow option for callback for response.json() vs response.text()
  • add timeout
  • add debounce
  • if 2nd param of post or one of the methods is a string treat it as query params
  • error handling if no url is passed
  • tests
  • port to typescript
  • badges
  • if no url is specified, and we're in the browser, use window.location.href
  • github page/website
  • support for a global context config where you can set base url's (like Apollo's client) but better ๐Ÿ˜‰
  • add GraphQL useQuery, useMutation
  • make GraphQL work with React Suspense

Mutations with Suspense (Not Implemented Yet)

const App = () => {
  const [todoTitle, setTodoTitle] = useState('')
  const mutation = useMutation('http://example.com', `
    mutation CreateTodo($todoTitle string) {
      todo(title: $todoTitle) {
        id
        title
      }
    }
  `)

  const createtodo = () => mutation.read({ todoTitle })
  
  if (!request.data) return null

  return (
    <>
      <input onChange={e => setTodoTitle(e.target.value)} />
      <button onClick={createTodo}>Create Todo</button>
      <pre>{mutation.data}</pre>
    </>
  )
}

About

๐Ÿถ React hook for making isomorphic http requests

License:MIT License


Languages

Language:TypeScript 100.0%