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
npm install @mongez/react-hooks
OR
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.
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.
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.
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.
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.
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 fromresponse.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.
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.
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.
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.
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.
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.
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.
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.
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, 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.
Salam.
Top comments (0)