useResource
This is a React custom hook meant for assisting in the retrieval of remote data and the caching of it once acquired using redux.
Setup
This project has two exports, the default which is the useResource
hook, and a { reducer }
.
import useResource, { reducer } from "@alexjamesmalcolm/use-resource";
Redux
Before being able to use the useResource
you must first include the reducer
into your rootReducer
import { createStore, combineReducers } from "redux";
import { reducer as useResource } from "@alexjamesmalcolm/use-resource";
const rootReducer = combineReducers({ useResource });
const store = createStore(rootReducer);
export default store;
It’s very important that the reducer is initialized as useResource
.
Wrapped in a Custom Hook
If you’re unfamiliar with custom hooks you can read about them in React’s documentation
It’s recommended that useResource
be used inside of a custom hook. For example you may want a hook that retrieves and pages through lists of breweries thanks to https://www.openbrewerydb.org/
import { useMemo, useCallback } from "react";
import useResource from "../../lib"; // normally from "@alexjamesmalcolm/use-resource";
interface Brewery {
id: number;
name: string;
brewery_type: string;
street: string;
city: string;
state: string;
postal_code: string;
country: string;
longitude: string;
latitude: string;
phone: string;
website_url: string;
updated_at: string;
tag_list: [];
}
const useBreweries = ({
pageNumber = 1,
pageSize = 10,
}: {
pageNumber?: number;
pageSize?: number;
} = {}) => {
const resourceId: string = useMemo(
() => `useBreweries: page ${pageNumber} with ${pageSize} per page`,
[pageNumber, pageSize]
);
const getResource = useCallback(
() =>
fetch(
`https://api.openbrewerydb.org/breweries?page=${pageNumber}&per_page=${pageSize}`
).then((response) => response.json()),
[pageNumber, pageSize]
);
const {
data,
error,
filterCache,
isInStore,
isLoading,
actions,
} = useResource(resourceId, { getResource });
return { breweries: data as Brewery[], error, isLoading };
};
export default useBreweries;
Using our Custom Hook in a Component
Then we implement useBreweries
in our example component:
import React, { useState, useCallback } from "react";
import useBreweries from "../../hooks/useBreweries";
const Setup = () => {
const [pageNumber, setPageNumber] = useState(1);
const { breweries, isLoading, error } = useBreweries({ pageNumber });
const previousPage = useCallback(
() => setPageNumber(Math.max(1, pageNumber - 1)),
[pageNumber]
);
const nextPage = useCallback(() => setPageNumber(pageNumber + 1), [
pageNumber,
]);
if (isLoading || !breweries) return <p>Loading breweries...</p>;
if (error) return <p>There was an error: {error.message}</p>;
return (
<>
<button onClick={previousPage}>Previous</button>
<button onClick={nextPage}>Next</button>
{breweries.map((brewery) => (
<div key={brewery.id}>
<p>{brewery.name}</p>
<p>{brewery.state}</p>
</div>
))}
<button onClick={previousPage}>Previous</button>
<button onClick={nextPage}>Next</button>
</>
);
};
export default Setup;