Is it possible to group react hooks?
I have several related custom hooks, e.g. useListProduct,useAddProduct.
In past, I can pack these functions into an object class but not the react component class. Here is an object class source code:
import {useAxios} from "./useAxios";
export class Product{
static useListProduct(){
let url="list product API URL";
return useAxios(null,"get",url);
}
static useAddProduct(product){
let url="list product API URL";
return useAxios(product,"post",url);
}
}
useAxios.js
import axios from "axios";
import { useEffect, useReducer } from 'react';
import { redirect } from "react-router-dom";
let reducer = (state, action) => {
let result = { ...state };
switch (action.type) {
case "updateData":
result.data = action.data;
result.isLoading = false;
break;
case "updateError":
result.error = action.error;
result.isLoading = false;
break;
default:
break;
}
return result;
}
export function useAxios(data, method, url, header, responseType) {
const [itemList, updateItemList] = useReducer(reducer, { data: undefined, error: undefined, isLoading: true });
useEffect(()=>{
let fetchApi = async () => {
let requestObj = { "method": method, "url": url }
if (method.toLowerCase() === "get") {
requestObj.params = data;
} else {
requestObj.data = data;
}
requestObj["responseType"] = responseType || undefined;
requestObj["headers"] = header || undefined;
try {
let result = await axios(requestObj);
updateItemList({ "data": result.data, type: "updateData" });
} catch (error) {
let errorObj;
if (error.response) {
switch (error.response.status) {
case 401:
alert(error.response.data);
redirect("/login");
break;
case 404:
errorObj = {
status: 404,
message: error.message
};
break;
default:
errorObj = {
status: error.response.status,
message: error.response.data
};
break;
}
} else {
errorObj = { message: error.message };
}
updateItemList({ "error": errorObj, type: "updateError" });
}
}
fetchApi();
},[]);
return [
itemList.isLoading,
itemList.data,
itemList.error
];
}
Unfortunately, react prompts the following message:
React Hook "useAxios" cannot be called in a class component. React Hooks must be called in a React function component or a custom React Hook function react-hooks/rules-of-hooks
So, what is the best pratice for grouping all related hooks together?
CodePudding user response:
Using static class methods as hooks would work during runtime, but the linter assumes that you are using a hook inside a class component (although it's not), which is forbidden by the rules of hooks.
An easy workaround would be to define them as separate functions, and then export them under a single object:
function useListProduct() {
let url="list product API URL";
return useAxios(null,"get",url);
}
function useAddProduct(product) {
let url="list product API URL";
return useAxios(product,"post",url);
}
export const Product = {
useListProduct,
useAddProduct,
}
Or export each as a named function, and then bundle them when importing or re-exporting:
export function useListProduct() {
let url="list product API URL";
return useAxios(null,"get",url);
}
export function useAddProduct(product) {
let url="list product API URL";
return useAxios(product,"post",url);
}
And then in another file:
import * as Product from './product';
or
export * as Product from './product';