jamesplease / react-request

Declarative HTTP requests for React
MIT License
362 stars 21 forks source link

useFetch hook #199

Open simonrelet opened 5 years ago

simonrelet commented 5 years ago

Hello, thanks for this package I've been using for several projects now and it helps a lot!

I didn't find any plans for a possible hook version of the Fetch component, so I transposed it into a useFetch hook and it felt that its place should be here.

Would you be willing take a PR for this?

The first two examples of the README would look like this (of course the name of the hook and the structure of its return value can be changed):

import React from 'react';
import { useFetch } from 'react-request';

function App() {
  const [post, { fetching, failed }] = useFetch({
    url: 'https://jsonplaceholder.typicode.com/posts/1'
  });

  if (fetching) {
    return <div>Loading data...</div>;
  }

  if (failed) {
    return <div>The request did not succeed.</div>;
  }

  if (post) {
    return (
      <div>
        <div>Post ID: {post.id}</div>
        <div>Post Title: {post.title}</div>
      </div>
    );
  }

  return null;
}

Multiple requests:

import React from 'react';
import { useFetch } from 'react-request';

function App() {
  const [post, readPost] = useFetch({
    url: 'https://jsonplaceholder.typicode.com/posts/1'
  });

  const [, deletePost] = useFetch({
    url: 'https://jsonplaceholder.typicode.com/posts/1',
    method: 'DELETE'
  });

  return (
    <div>
      {readPost.fetching && 'Loading post 1'}
      {!readPost.fetching && 'Post 1 is not being fetched'}
      <button onClick={() => deletePost.doFetch()}>
        Delete Post 1
      </button>
    </div>
  );
}
jamesplease commented 5 years ago

:wave: hey there @simonrelet ! I appreciate you taking the time to open this issue!

Would you be willing take a PR for this?

I'm definitely open to it. I want to be mindful of file-size, as someone using the hook version on a brand-new project most likely wouldn't use the render props version. How big is the hook lookin'?

I didn't find any plans for a possible hook version of the Fetch component...

Yeah, that's true. Part of the reason for a lack of a roadmap update is that, to be honest, I'm undecided on what it should look like. Once Suspense has docs for making network requests, and we have a reference cache (react-cache), this approach to making network requests, be it a hook or a render prop component, will likely fall out of favor. So I think that React Request and anything like it has a limited life ahead of it.

On an entirely separate note came up with an alternative props API that I think offers considerable benefits over the current set of props, and I've been using the hooks version of that on side projects with a great deal of success. However, given that:

  1. Suspense could potentially be right around the corner
  2. it was a boatload of work to create this project and fix all of the bugs, etc.

I'm not sure if it's worth investing the time to make a standalone lib for it πŸ€”

What do you think?

simonrelet commented 5 years ago

Hi @jamesplease ! Thanks for the quick answer.

How big is the hook lookin'?

It's 400 lines which make the gzipped ~4kb. Here's the hook.

Maybe adding a "sideEffects": false entry in the package.json would allow apps using Webpack 4 to tree shake the unused parts.

Yeah, that's true. Part of the reason for a lack of a roadmap update is that, to be honest, I'm undecided on what it should look like. Once Suspense has docs for making network requests, and we have a reference cache (react-cache), this approach to making network requests, be it a hook or a render prop component, will likely fall out of favor. So I think that React Request and anything like it has a limited life ahead of it.

I understand and agree. I'm just looking for a temporary solution until the Suspense API comes out, and though maybe this was the good place for that. That being said I totally understand the work that come with it might not be worth it.

On an entirely separate note came up with an alternative props API that I think offers considerable benefits over the current set of props, and I've been using the hooks version of that on side projects with a great deal of success.

Is this alternative API a public package? I might be just what I/we need for now πŸ˜….

jamesplease commented 5 years ago

It's 400 lines which make the gzipped ~4kb. Here's the hook.

Maybe adding a "sideEffects": false entry in the package.json would allow apps using Webpack 4 to tree shake the unused parts.

Cool, cool. I'm working on some other projects atm, and about to go on vacation for awhile, but I've added this to my todo list as something to explore.

I'm just looking for a temporary solution until the Suspense API comes out, and though maybe this was the good place for that. That being said I totally understand the work that come with it might not be worth it.

:+1:

Is this alternative API a public package? I might be just what I/we need for now πŸ˜….

It's not a public package atm, just due to the overhead in maintenance. And, also, I'm still working on the API, so I wouldn't want to publish something that's still in such a rough state. But the tl;dr is that you don't describe a network request in the props/options: you pass it a Promise that resolves with a particular structure (I call this Promise a "fetcher").

Note that the API is still very, very rough, but here's a quick example:

const fetchBooksRequest = useFetcher(
    () =>
      fetchBooks({
        bookId
      }),
    {
      lazy: true,
      condition: [bookId]
    }
  );

fetchBooksRequest: has a nearly identical shape as the object passed to the render prop in React Request. lazy: just like lazy in React Request condition: mimics the automatic fetch behavior when props change (it's effectively the 2nd arg of useEffect)

The benefits of this approach are:

  1. The config of the network request is abstracted into fetchBooks. fetchBooks can be used in many different contexts: a Suspense cache, useFetcher, or an alternative version of React Request that accepts fetchers.
  2. You can more easily handle serial and parallel requests, because Promises are pretty good at that (for more, see: https://github.com/jamesplease/react-request/issues/59 )
jamesplease commented 5 years ago

Btw here's a gist of a mostly-functioning hook for network requests. The code isn't the most tidy, as I just typed it up really quickly to test it out (it may or may not work atm, and it may or may not have bugs πŸ˜› ).

Although I'm undecided if I'll make that into a standalone library, that is the general approach I would recommend taking for making a fetch hook, as it solves some of the problems inherent in React Request's API.

Notes

FAQ

Do I plan to tidy up/finalize the hook's code in the gist?

Possibly, but maybe not. It's forming the foundation of a new, more powerful library that I will be tidied up/published on npm.

Why am I hesitant on making that into a standalone lib?

It takes time to do that, and I'm more interested in what I'll be building on top of it atm. Plus, Suspense is right around the corner, so all of this might be wasted effort... πŸ˜‰

simonrelet commented 5 years ago

Sorry for the late reply.

Thanks for the answers, I like the idea of a generic fetcher.

I'll have a look at the gist, thanks.