useFetcher: the easiest way to fetch data in React
Tags: react, router, mongez
Published: 2022-10-13 08:08:21

---
title: useFetcher: the easiest way to fetch data in React
published: true
description: 
tags: reactjs, router, mongez
# cover_image: https://direct_url_to_image.jpg
# Use a ratio of 100:42 for best results.
---

## Introduction

The `useFetcher` hook is a React hook that makes it easy to fetch data from the server. It provides you with tons of features to facilitate your work with APIs specially if you're working on page that display lists with pagination, sorting or searching, this is your way to go with.

## Installation

```bash
npm install @mongez/react-hooks
```

OR

```bash
yarn add @mongez/react-hooks
```

## Usage

The `useFetcher` hook accepts a function that returns a promise, this function is your api request (axios) that receives list of params and returns a promise.

> `If you feel this article will be useful to you don't forget to share it with your friends and support me.`

```tsx
import { useFetcher } from '@mongez/react-hooks';

const getUsers = (params) => {
    return axios.get('/api/users', { params });
};

const Users = () => {
    const { records, isLoading, error } = useFetcher(getUsers);

    if (isLoading) return <p>Loading...</p>;

    if (error) return <p>Something Went Wrong</p>;

    return (
        <div>
            {records.map(user => <p key={user.id}>{user.name}</p>)}
        </div>
    );
};
```

Pretty easy right? now let's see what else you can do with it.

### Pagination

If the response of the api `getUsers` returns pagination details, then these details will be transformed into some properties you can use in your component, let's start with `loadMore` feature.

```tsx
import { useFetcher } from '@mongez/react-hooks';

const getUsers = (params) => {
    return axios.get('/api/users', { params });
};

const Users = () => {
    const { records, isLoading, error, loadMore } = useFetcher(getUsers);

    if (isLoading) return <p>Loading...</p>;

    if (error) return <p>Something Went Wrong</p>;

    return (
        <div>
            {records.map(user => <p key={user.id}>{user.name}</p>)}

            <button onClick={loadMore}>Load More</button>
        </div>
    );
};
```

Now this will work if the response of the api returns pagination details, it will depend on the `goToPage` method that allow you to navigate to a specific page, let's see how to use it.

```tsx
import { useFetcher } from '@mongez/react-hooks';

const getUsers = (params) => {
    return axios.get('/api/users', { params });
};

const Users = () => {
    const { records, isLoading, error, goToPage } = useFetcher(getUsers);

    if (isLoading) return <p>Loading...</p>;

    if (error) return <p>Something Went Wrong</p>;

    return (
        <div>
            {records.map(user => <p key={user.id}>{user.name}</p>)}

            <button onClick={() => goToPage(2)}>Go To Page 2</button>
        </div>
    );
};
```

This will work exactly as the previous example, but `loadMore` is useful if you're not working with pagination, for example when dealing lazy loading by scrolling or by the load more button.

The question here, how does the fetcher know the keys of the pagination, well there are predefined keys that you can use, but you can also change them to whatever you want, let's see how.

```tsx
import { useFetcher } from '@mongez/react-hooks';

const getUsers = (params) => {
  return axios.get("/api/users", { params });
};

const Users = () => {
  const { records, isLoading, error, goToPage } = useFetcher(getUsers, {
    keys: {
      records: "records",
      itemsPerPage: "meta.itemsPerPage",
      currentPage: "meta.currentPage",
      currentRecords: "meta.currentRecords",
      totalPages: "meta.totalPages",
      totalRecords: "meta.totalRecords",
      pageNumber: "page",
    },
  });

  if (isLoading) return <p>Loading...</p>;

  if (error) return <p>Something Went Wrong</p>;

  return (
    <div>
      {records.map((user) => (
        <p key={user.id}>{user.name}</p>
      ))}

      <button onClick={() => goToPage(2)}>Go To Page 2</button>
    </div>
  );
};
```

As you can see, you can change the keys of the pagination to whatever you want, but you have to make sure that the response of the api returns the same keys as you specify them, here are the default keys that are being used.

```tsx
const defaultOptions = {
  keys: {
    records: "records",
    itemsPerPage: "paginationInfo.itemsPerPage",
    currentPage: "paginationInfo.currentPage",
    currentRecords: "paginationInfo.currentRecords",
    totalPages: "paginationInfo.totalPages",
    totalRecords: "paginationInfo.totalRecords",
    pageNumber: "page",
  },
};
```

The records key is the key that contains the list of records, the rest of the keys are used to calculate the pagination details.

> Dot Notation is supported, so you can use `paginationInfo.itemsPerPage` to be taken from `response.data` object.

## Override Default Fetch Options

Instead of modifying the keys of the pagination, you can also override the default fetch options, let's see how.

```tsx
import { useFetcher, setFetchOptions } from '@mongez/react-hooks';

// somewhere in your app

setFetchOptions({
  keys: {
    records: "records",
    itemsPerPage: "meta.itemsPerPage",
    currentPage: "meta.currentPage",
    currentRecords: "meta.currentRecords",
    totalPages: "meta.totalPages",
    totalRecords: "meta.totalRecords",
    pageNumber: "page",
  },
});

const getUsers = (params) => {
  return axios.get("/api/users", { params });
};

const Users = () => {
  const { records, isLoading, error, goToPage } = useFetcher(getUsers);

  if (isLoading) return <p>Loading...</p>;

  if (error) return <p>Something Went Wrong</p>;

  return (
    <div>
      {records.map((user) => (
        <p key={user.id}>{user.name}</p>
      ))}

      <button onClick={() => goToPage(2)}>Go To Page 2</button>
    </div>
  );
};
```

## Knowing When To Fetch

There are some useful properties keys hat you can use as indicators whether to allow loading more data or even pagination or not, for instance using `paginatable` property you can know whether you should display the pagination list or the load more button.

```tsx
import { useFetcher } from '@mongez/react-hooks';

const getUsers = (params) => {
  return axios.get("/api/users", { params });
};

const Users = () => {
  const { records, isLoading, error, goToPage, paginatable } = useFetcher(getUsers);

  if (isLoading) return <p>Loading...</p>;

  if (error) return <p>Something Went Wrong</p>;

  return (
    <div>
      {records.map((user) => (
        <p key={user.id}>{user.name}</p>
      ))}

      {paginatable && <button onClick={() => goToPage(2)}>Go To Page 2</button>}
    </div>
  );
};
```

### Knowing the current page and total pages

You can also use `currentPage` and `totalPages` properties to know where you are now and how many pages you should display.

```tsx
import { useFetcher } from '@mongez/react-hooks';

const getUsers = (params) => {
  return axios.get("/api/users", { params });
};

const Users = () => {
  const { records, isLoading, error, goToPage, paginatable, currentPage, totalPages } = useFetcher(getUsers);

  if (isLoading) return <p>Loading...</p>;

  if (error) return <p>Something Went Wrong</p>;

  const pages = [];

  for (let i = 1; i <= totalPages; i++) {
    pages.push(i);
  }

  return (
    <div>
      {records.map((user) => (
        <p key={user.id}>{user.name}</p>
      ))}

      {paginatable && (
        <div>
          <button onClick={() => goToPage(currentPage - 1)}>Previous</button>
          {pages.map((page) => (
            <button key={page} onClick={() => goToPage(page)}>
              {page}
            </button>
          ))}
          <button onClick={() => goToPage(currentPage + 1)}>Next</button>
        </div>
      )}
    </div>
  );
};
```

In the previous example, we combined all useful keys together, the `totalPages` to tell you how many pages you should display, the `currentPage` to tell you where you are now, and the `paginatable` to tell you whether you should display the pagination or not.

### The First And last Page

You can also use `isLastPage` property to know whether you are on the last page or not, also `isFirstPage` to know whether you are on the first page or not.

```tsx
import { useFetcher } from '@mongez/react-hooks';

const getUsers = (params) => {
  return axios.get("/api/users", { params });
};

const Users = () => {
  const { records, isLoading, error, goToPage, paginatable, currentPage, totalPages, isFirstPage, isLastPage } = useFetcher(getUsers);

  if (isLoading) return <p>Loading...</p>;

  if (error) return <p>Something Went Wrong</p>;

  const pages = [];

  for (let i = 1; i <= totalPages; i++) {
    pages.push(i);
  }

  return (
    <div>
      {records.map((user) => (
        <p key={user.id}>{user.name}</p>
      ))}

      {paginatable && (
        <div>
        {! isFirstPage && <button onClick={() => goToPage(currentPage - 1)}>Previous</button>}
          {pages.map((page) => (
            <button key={page} onClick={() => goToPage(page)}>
              {page}
            </button>
          ))}
          {!isLastPage && <button onClick={() => goToPage(currentPage + 1)}>Next</button>}
        </div>
      )}
    </div>
  );
};
```

## Default Params

You can also set default params that will be sent with every request using `defaultParams` property.

```tsx
import { useFetcher } from '@mongez/react-hooks';

const getUsers = (params) => {
  return axios.get("/api/users", { params });
};

const Users = () => {
  const { records, isLoading, error } = useFetcher(getUsers, {
    defaultParams: {
      status: "active",
    },
  });

  if (isLoading) return <p>Loading...</p>;

  if (error) return <p>Something Went Wrong</p>;

  return (
    <div>
      {records.map((user) => (
        <p key={user.id}>{user.name}</p>
      ))}
    </div>
  );
};
```

The `defaultParams` object will be merged with the params object that will be passed to the fetch method `getUser` on every request.

## Load, Reset and Reload

Another useful feature of the `useFetcher` hook is the ability to load, reset and reload the data, the `load` method will allow you to customize your request params (apart from `defaultParams`), the `reset` method will recall the initial request which includes the default params data, and the `reload` method will recall the last request.

```tsx
import { useFetcher } from '@mongez/react-hooks';

const getUsers = (params) => {
  return axios.get("/api/users", { params });
};

const Users = () => {
  const { records, isLoading, error, load, reset, reload } = useFetcher(getUsers, {
    defaultParams: {
      status: "active",
    },
  });

  if (isLoading) return <p>Loading...</p>;

  if (error) return <p>Something Went Wrong</p>;

  return (
    <div>
      {records.map((user) => (
        <p key={user.id}>{user.name}</p>
      ))}

      <button onClick={() => load({ status: "inactive" })}>Load Inactive Users</button>
      <button onClick={() => reset()}>Reset</button>
      <button onClick={() => reload()}>Reload</button>
    </div>
  );
};
```

## Current And Total Records

The last piece of information that you can get from the `useFetcher` hook is the `currentRecords` and `totalRecords` properties, the `currentRecords` will tell you how many records are currently loaded, and the `totalRecords` will tell you how many records are there in total.

```tsx
import { useFetcher } from '@mongez/react-hooks';

const getUsers = (params) => {
  return axios.get("/api/users", { params });
};

const Users = () => {
  const { records, isLoading, error, currentRecords, totalRecords } = useFetcher(getUsers);

  if (isLoading) return <p>Loading...</p>;

  if (error) return <p>Something Went Wrong</p>;

  return (
    <div>
      {records.map((user) => (
        <p key={user.id}>{user.name}</p>
      ))}

      <p>
        Showing {currentRecords} of {totalRecords}
      </p>
    </div>
  );
};
```

## Entire Response

The `useFetcher` hook will return the entire response object from the request, so you can access any property from it using `response` property.

```tsx
import { useFetcher } from '@mongez/react-hooks';

const getUsers = (params) => {
  return axios.get("/api/users", { params });
};

const Users = () => {
  const { records, isLoading, error, response } = useFetcher(getUsers);

  if (isLoading) return <p>Loading...</p>;

  if (error) return <p>Something Went Wrong</p>;

  return (
    <div>
      {records.map((user) => (
        <p key={user.id}>{user.name}</p>
      ))}

      <p>
        Showing {response.data.current_page} of {response.data.last_page}
      </p>
    </div>
  );
};
```

## Bonus

If you want a simple hook with no pagination, you can use [useRequest hook](https://github.com/hassanzohdy/react-hooks#userequest), it will return three properties only `response` `isLoading` and `error`.

## Conclusion

I hope you enjoy this hook, `@mongez/react-hooks` has another useful hooks you can use but this will be in another night.

For more documentation check the [Github repository](https://github.com/hassanzohdy/react-hooks).

Salam.