Giter Club home page Giter Club logo

react-fetch-hook's Introduction

react-fetch-hook

CircleCI npm version npm downloads

React hook for conveniently use Fetch API.

  • Tiny (556 B). Calculated by size-limit
  • Both Flow and TypeScript types included
import React from "react";
import useFetch from "react-fetch-hook";

const Component = () => {
  const { isLoading, data } = useFetch("https://swapi.co/api/people/1");

  return isLoading ? (
    <div>Loading...</div>
  ) : (
    <UserProfile {...data} />
  );
};

useFetch accepts the same arguments as fetch function.

Installation

Install it with yarn:

yarn add react-fetch-hook

Or with npm:

npm i react-fetch-hook --save

Usage

Custom formatter

Default is response => response.json() formatter. You can pass custom formatter:

const { isLoading, data } = useFetch("https://swapi.co/api/people/1", {
    formatter: (response) => response.text()
});

Error handling

The useFetch hook returns an error field at any fetch exception. The error field extends Error and has status and statusText fields equal to Response.

...

const Component = () => {
  const { isLoading, data, error } = useFetch("https://swapi.co/api/people/1");

  if (error) {
    return <div>
      <p>Code: ${error.status}</p>
      <p>Message: ${error.statusText}</p>
    </div>
  }
 
  ...
};

Multiple requests

Multiple useFetch in the same file/component supported:

const result1 = useFetch("https://swapi.co/api/people/1");
const result2 = useFetch("https://swapi.co/api/people/2");

if (result1.isLoading && result2.isLoading) {
  return <div>Loading...</div>;
}  

return <div>
    <UserProfile {...result1.data} />
    <UserProfile {...result2.data} />
</div>

Depends

The request will not be called until all elements of depends array be truthy. Example:

const {authToken} = useContext(authTokenContext);
const [someState, setSomeState] = useState(false);
const { isLoading, data } = useFetch("https://swapi.co/api/people/1", {
    depends: [!!authToken, someState] // don't call request, if haven't authToken OR someState: false
});

See example.

Re-call requests

If any element of depends changed, request will be re-call. For example, you can use react-use-trigger for re-call the request:

import createTrigger from "react-use-trigger";
import useTrigger from "react-use-trigger/useTrigger";

const requestTrigger = createTrigger();

export const Subscriber = () => {  
    const requestTriggerValue = useTrigger(requestTrigger);
    
    const { isLoading, data } = useFetch("https://swapi.co/api/people/1", {
        depends: [requestTriggerValue]
    });
  
    return <div />;
}

export const Sender = () => { 
    return <button onClick={() => {
        requestTrigger() // re-call request
    }}>Send</button>
}

usePromise

For custom promised function.

import React from "react";
import usePromise from "react-fetch-hook/usePromise";
import callPromise from "..."

const Component = () => {
  const { isLoading, data } = usePromise(() => callPromise(...params), [...params]);

  return isLoading ? (
    <div>Loading...</div>
  ) : (
    <UserProfile {...data} />
  );
};
  • Basic - Just fetch data with useFetch.
  • Depends - Usage depends option for refresh query.
  • Pagination - Usage usePaginationRequest for infinite scroll implementation.

API

useFetch

Create a hook wrapper for fetch call.

useFetch(
    path: RequestInfo,
    options?: {
        ...RequestOptions,
        formatter?: Response => Promise
        depends?: Array<boolean>
    },
    specialOptions?: {
        formatter?: Response => Promise
        depends?: Array<boolean>
    }
): TUseFetchResult

where TUseFetchResult is:

{
    data: any,
    isLoading: boolean,
    error: any
}

RequestInfo, RequestOptions is fetch args.

usePromise

usePromise<T, I: $ReadOnlyArray<mixed>>(
    callFunction: ?(...args: I) => Promise<T>,
    ...inputs: I
): TUsePromiseResult<T>

where TUsePromiseResult<T> is

type TUsePromiseResult<T> = {
    data: ?T,
    isLoading: boolean,
    error: mixed
}

Experimental: usePaginatedRequest

⚠️ Warning: this method is experimental, API can be changed.

Create a paginated request.

usePaginatedRequest = <T>(
    request: (params: { limit: number, offset: number }) => Promise<Array<T>>,
    limit: number,
    ...depends: Array<any>
): {
    data: Array<T>,
    loadMore?: () => mixed,
    hasMore: boolean
};

Who Uses react-fetch-hook

Open Source projects

Companies

See more

react-fetch-hook's People

Contributors

dependabot[bot] avatar ilyalesik avatar pret-a-porter avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-fetch-hook's Issues

breaks with `useState`/`useEffect`

data is loaded fine (1. log), but once I call useState or useEffect, the code after (2. log) is no longer executed.
Not sure what's going on. No exception thrown. Works fine with plain fetch.
Did I miss something?

import useFetch from 'react-fetch-hook'; // 1.9.5

const UserTable = () => {
  const [users, setUsers] = useState([]);
  const { isLoading, data, error } = useFetch('/admin/users');
  console.log('data', isLoading, data, error);
  if (isLoading || !data) return 'Loading...';
  if (error) return 'An error has occurred: ' + error.message;
  // setUsers([]); // if called, the following code  is dead
  // useEffect(() => { console.log('data changed') }, [data]); // same with this
  console.log('data2', data);
};

useFetch never fetches if the depends array includes values like an empty string or null

It seems like useFetch never fetches data if the depends is something like [''], but sets isLoading to false immediately, i.e. pretending like it finished loading, but just producing the value undefined. This means that if the value in the depends array is a string that might sometimes be empty, data might just happen to be undefined so any code that expects data to exist if isLoading is false fails.

Full component example:

import useFetch from "react-fetch-hook";


function App() {
  const { isLoading, data } = useFetch("https://api.github.com/", {depends:['']});
  console.log(data);
  return (   
    <p>
      {JSON.stringify(data)}
    </p>
  );
}

export default App;

I'm not sure if this is intended or not, but given that there are situations where depends might include a sometimes empty string, I assume not.

Rerender triggered three times when dependencies change

This may be related to #24. Whenever I change the dependencies, I get three rerenders where I only expect to see two.

Expected:

  1. Change dependencies.
  2. Render with isLoading === true, data === null
  3. Render with isLoading === false, data === <new-result>

Actual:

  1. Change dependencies.
  2. Render with isLoading === false, data === <previous-result>
  3. Render with isLoading === true, data === <previous-result>
  4. Render with isLoading === false, data === <new-result>

I don't care so much about data containing the previous result, and changing just that to null with no additional changes would be bad. But why am I getting that first rerender which is a copy of the previous call result? I would expect calling the hook with changed dependencies to immediately return with isLoading === true.

To be clear, everything works okay. The downside is the additional no-op render due to the first result being identical to the previous result. I assume the fetch call has been made by that point, and yet the hook tells me it's not loading. Is there any way to avoid that (step 2 above)?

README typo misleading

const {authToken} = useContext(authTokenContext);
const [someState, setSomeState] = useState(false);
const { isLoading, data } = useFetch("https://swapi.co/api/people/1", {
    depends: [!!authToken, someState] //don't call request, if haven't authToken and someState: false
});

The above should read: don't call request, if haven't authToken OR someState: false. Unless I've misunderstood.

"isLoading" changes to true also if the "depends" field is false

When the isValidMail variable is false the data is correctly set to undefined but the isLoading changes to true.

const isValidMail = !validator_email(orgEmail).error
const {isLoading, data} = useFetch(`https://satec.cynation.com/api/v1/accounts/search/org?api-key=8a0b7868-57c8-430e-95a9-de915ff2b7d8&email=${orgEmail}`,{
    depends: [isValidMail]
  })

DevTool log (isValidMail=false):

isLoading: false index.js:91
data: undefined index.js:92
isLoading: true index.js:91
data: undefined index.js:92
isLoading: false index.js:91
data: undefined

DevTool log (isValidMail=true):

isLoading: false index.js:91
data: undefined index.js:92
isLoading: true index.js:91
data: undefined index.js:92
isLoading: false index.js:91
data: 
Object { orgId: "2c5168a8-1b5b-474e-96f8-f62e9dd51231", orgName: "Example" }

isLoading = false with rapid requests

If rapid requests are issued, like in an autocomplete scenario, isLoading will be false even when hanging requests are still open.

In other words:

  1. Setup a series of fetches quickly as the user is typing
  2. When a new fetch is issued, cancel the previous fetches
  3. isLoading will === false even though current fetch is still open
  4. results will still correctly return

how determine the error status code

Hi
I have a question about the error message. Currently I receive a string but it would be nice to show different message based on the response status - like 401 or 500.
Is there a way to do this?
Thanks!

Abort fetch

Hi thank you for this great react fetch hook,
Is there a way to make the fetch abortable and abort it when component is unmount ?

Thank you

isLoading is initially false

Hello,

I just tried out your lib. In use with useFetch, would it not be better to set isLoading initially to true? Otherwise the component initially would render as its not loading and a wrong component/logic could run.

Just an idea while testing this hook
Cheers

Fetch some data and only then fetch some one

Hi! First of all, many thanks for a good tool, I use it in my project and it helps me a lot to keep the code clean.

Recently I needed to fetch some data and only then fetch other data that would be based on the result of the first fetch.

I try something like this. But as I understand it's doesn't working because hooks limitations.

  const { isLoading, data: repoData } = useFetch(`${endpoint.github}repos/${repo}`, {
    headers: new Headers({
      Authorization: `token ${process.env.GITHUB_TOKEN}`,
    })
  });

  if (!isLoading) {
    const userAPIUrl = repoData.owner.url; // Get this staff from another hook

    const { data: userData } = useFetch(`${endpoint.github}users/${userAPIUrl}`, {
      headers: new Headers({
        Authorization: `token ${process.env.GITHUB_TOKEN}`,
      })
    });
  }

Any ideas how I can implement it in a different way? I am not currently a React guru and I would be very grateful for any help in this case.

Implementation for Graphql query ?

Hi there,

Is there any implementation of react-fetch-hook for GraphQL ?
For example, the typical GraphQL query:

const MY_QUERY_QUERY = gql`
  query MyQuery {
    auth_user {
      email
      first_name
      id
      is_active
      last_name
      last_login
      username
    }
  }
`;

How to implement this query ?
Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.