I'm building a react app for an eCommerce site. I have a page for Product Search. I'm using the SWR library (useSWR hook), because I like it's caching ability. However, as it uses hooks, it seems I can't place this call outside of my function component. Ideally, I'd like to segment off all API functionality into a separate library / service layer.
Let me demonstrate what I'm trying to do with some extremely cut-down code:
import React, { useState } from 'react';
import { useParams } from "react-router";
import * as ProductAPI from 'common/libs/ProductAPI';
function ProductSearch() {
    const [searchResults, setSearchResults] = useState(null);
    let { keywords } = useParams();
    const results = ProductAPI.getProductSearchResults(keywords);
    if (searchResults != results)
        setSearchResults(results);
    function renderSearchResults() {
        ...
    }
    return (
        <>
            {renderSearchResults()}
        </>
    );
}
export default ProductSearch;
And the API library:
import useSWR from 'swr';
var productSearchURL = process.env.REACT_APP_API_ENDPOINT + '/product/search';
export function getProductSearchResults(keywords) {
    let url = productSearchURL;
    url += "/" + encodeURI(keywords);
    const { data } = useSWR(url);
    return data;
}
Now, React is giving met the "you're breaking the rules of hooks" error:
Invalid hook call. Hooks can only be called inside of the body of a function component.
I've been struggling to find a solution that would let me achieve this abstraction of API functionality into it's own function/component.
If there's no way to solve this using my current approach, what would be the best way to achieve this layered approach to the API implementation?
You should create a custom hook that uses useSWR to fetch data. React will allow to create a custom hook with other hooks used inside it. Somthing like this:
export function useProductSearchResults(keywords) {
    let url = productSearchURL;
    url += "/" + encodeURI(keywords);
    const { data } = useSWR(url);
    return data;
}
then use this custom hook in you code:
.
.
 let { keywords } = useParams();
    const results = useProductSearchResults(keywords);
    if (searchResults != results)
        setSearchResults(results);
.
.
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With