Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/chandrakantap/remote-resource-toolkit
Simple React hooks to avoid redux boilerplate and fetching remote data. Fetched data is cached in redux.
https://github.com/chandrakantap/remote-resource-toolkit
redux redux-boilerplate
Last synced: 10 days ago
JSON representation
Simple React hooks to avoid redux boilerplate and fetching remote data. Fetched data is cached in redux.
- Host: GitHub
- URL: https://github.com/chandrakantap/remote-resource-toolkit
- Owner: chandrakantap
- License: mit
- Created: 2023-02-02T22:33:10.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2023-02-05T11:56:23.000Z (almost 2 years ago)
- Last Synced: 2024-10-23T01:10:12.231Z (3 months ago)
- Topics: redux, redux-boilerplate
- Language: TypeScript
- Homepage:
- Size: 93.8 KB
- Stars: 0
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
## Remote Resource Toolkit
Simple React hooks to avoid redux boilerplate and fetching remote data. Fetched data is cached in redux.
Most of the React projects I worked on use redux as a state management solution. Even with the recommended Redux toolkit I noticed repetitive codes while writing redux logic for different portion of the application.
I thought of developing a common react hook which sums up most of the actions that performed on a state slice. So that I can avoid writing slice for different remote data in project
The idea is to have a common redux slice, say, remoteResource and other slices will be added/removed dynamically under it.
## What is Remote resource?
This hook view a remote resource as a combination of two things, `resource data` and `parameters(query params + request body)`. So all remote resource under redux structured as below:```
interface RemoteResource {
status: ApiCallStatus;
resource?: ResourceType;
resourceKey?: string;
resourceParams?: ResourceParams;
message?: string;
}
```
The above structure get added/removed under `state.remoteResource` when `useRemoteResource` called.## How to use
### Add the common slice to the store
```typescript
import {remoteResourceReducer} from '@cksutils/remote-resource-toolkit';export const store = configureStore({
reducer: {
remoteResource: remoteResourceReducer,
},
});
```
That's it no need to create any slice in the application, instead use `useRemoteResource` to load data.### Create your own hooks using `useRemoteResource` for loading a specific type of resource.
Say, we want to load `products` from api `/api/products`. `sortByColumn` product name and `perPage` 20 items
```typescript
import {ResourceLoaderFn} from '@cksutils/remote-resource-toolkit';// ResourceType, which is taken as items and totalCount
type ProductList = { items: ProductModel[]; totalCount: number };// This Resource params
const deafultQueryParams: ResourceFilters = {
page: 1,
perPage: 20,
sortByColumn: 'name',
sortOrder: 'asc',
};/**
* We have to provide a resource loader function.
* It takes below argument
* args: {
* params: Partial;
* abortSignal?: AbortSignal;
* }
* abortsignal to abort the network call if component unmounts before response
* and return type is
* Promise<{ success: boolean; data?: ResourceType; params?: Params; message?: string }>;
**/
const resourceLoader: ResourceLoaderFn = async (args) => {
try {
const { data } = await axios.get('/api/products', {
params: {
...deafultQueryParams,
...args.params,
},
signal: args?.abortSignal,
});
return {
success: data.success,
data: {
items: data?.data?.products,
totalCount: data?.data?.total_count,
},
message: data?.message,
};
} catch (e) {
return { success: false };
}
};const useProductList = (params: { autoLoad?: boolean; autoRemove?: boolean } = EMPTY_OBJECT) => {
const {
status,
resource,
resourceParams = deafultQueryParams,
loadData,
} = useRemoteResource({
resourceName: 'products',// this string will be used to add in redux, so data will be available at state.remoteResource.products
autoLoad: params.autoLoad, // whether to load data on mount
autoRemove: params.autoRemove, // whether to remove from redux on unmount
resourceLoader, // the resource loader function
});// Compose some custom methods from the useRemoteResource
const moveToPage = async (page: number) => {
return loadData({ page });
};const searchProduct = (searchText: string) => loadData({ searchText });
return {
isLoading: status === 'IN_PROGRESS',
status,
items: resource?.items || EMPTY_ARRAY,
totalCount: resource?.totalCount || 0,
filters: resourceParams,
loadProducts: loadData,
refreshData: loadData,
moveToPage,
searchProduct,
};
};export default useProductList;
```### Use the customHook to load product data anywhere
```typescript
// ProductList.tsx
import useProductList from './useProductList';export function productList(){
const {isLoading, items,filters, moveToPage } = useProductList({autoLoad: true});return(
NamePrice
{item.map(product=>(
{product.name}
product.price
)}
)
}
```