Home > database >  How to use custom hooks if data being passed to the hook needs to be modified beforehand?
How to use custom hooks if data being passed to the hook needs to be modified beforehand?

Time:01-25

I am developing a web application using react. In my project there were multiple instances where I had to send a GET request to the server and receive data and loading status. So I built a custom hook for the same

Here is the custom hook:

export const useGetApi = (link) => {
    const [data, setData] = useState();
    const [loading, setLoading] = useState(true);

    const handleFetch = async () => {
        const cancelToken = axios.CancelToken.source();
        try {
            const response = await axios.get(link, { cancelToken: cancelToken.token });
            setLoading(false);
            setData(response.data.data);
        } catch (err) {
            setLoading(true);
            //handle error
        }
    };

    useEffect(() => {
        handleFetch();
    }, [JSON.stringify(data)]);

    return [data, loading];
};

For most cases, it works I only have to pass the link as an argument to the hook. But in some instances, I have the requirement where I will have to first modify the link and then pass the modified link to the hook as a parameter.

I tried to achieve this using:

export const App=()=>{
    const link='/helloworld'
    const modifiedLink= getModifiedLink(link);

    useEffect(()=>{
       const [data,loading]= useGetApi(modifiedLink);
    },[])

}

I get errors as:

React Hook "useGetApi" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function.

Do I need to make a separate hook for the cases where the link is modified first and then passed? Because this will lead to a lot of repeatable code. Is there a way to use my existing hook and still fulfill my requirement. Please guide me.

CodePudding user response:

Like React hooks, Custom hooks cannot be called conditionally, inside another hook or in a loop. Custom or not hooks need to be called the top level of the component.

There are several mistakes in your code:

  1. your custom hook is only running once and if you want to refech it like using useEffect (I can see you tried to do this with another useEffect) you can pass the keys to your custom hooks useEffect keys. That way you can refech the query whenever you want.
export const useGetApi = (link) => {
    const [data, setData] = useState();
    const [loading, setLoading] = useState(true);

    const handleFetch = async () => {
        const cancelToken = axios.CancelToken.source();
        try {
            const response = await axios.get(link, { cancelToken: cancelToken.token });
            setLoading(false);
            setData(response.data.data);
        } catch (err) {
            setLoading(true);
            //handle error
        }
    };

    useEffect(() => {
        handleFetch();
    }, [link]); // this way your query runs whenever your link changes

    return [data, loading];
};
  1. Using your custom hook inside another hook:
export const App=()=>{
    const link='/helloworld'
    const modifiedLink= getModifiedLink(link);
    const [data,loading]= useGetApi(modifiedLink); // this is the true way

}

You can put the link in a useState hook and send it to your useGetApi so whenever the link changes your query will re-fetch.

I suggest you to use react-query, it basically does what you trying to do here but more stable and easy-to-use approach.

  • Related