'Using Custom Hook with search parameters

next it's a code that uses a HOC for showing some components while a fetch (with a custom hook) to an API REST is made.

From useSearchParams() I get the query string that will be used in fetching data.

The issue here is that when the component is rendered useFetch is executed but the search parameter (param) is not ready, then fetch is executed with null value.

const withLoading = (WrappedComponent) => {
    const HocComponent = ({ ...props }) => {
        const [urlParams, setUrlParams] = useSearchParams()
        const [param, setParam] = useState()
        useEffect(() => {
            console.log(urlParams.get("text"));
            setParam(urlParams.get("text"))
        }, [urlParams])
        const { data, loading, error } = useFetch("api_server", "/articles", { 'text': param })
        if (loading) return (
            <div className="grid grid-cols-6">
                {Array(6).map(el => <ProductPulse />)}
            </div>
        )
        return <WrappedComponent data={data} error={error} />
    }
    return HocComponent
}

Any comments on how to solve this issue using the hook useFetch?

I've tried many different ways without any luck.

I'm specting to use the custom hook useFetch in this scenario.



Solution 1:[1]

The issue with the current implementation is that you are caching the text queryString parameter in state, which delays the param state value being available by at least one render cycle.

The fix is trivial though, just consume the text queryString parameter directly, there's no need for any param state.

Example:

const withLoading = Component => props => {
  const [urlParams] = useSearchParams();

  const param = urlParams.get("text");

  const { data, loading, error } = useFetch(
    "api_server",
    "/articles",
    { text: param },
  );

  if (loading) {
    return (
      <div className="grid grid-cols-6">
        {Array(6).map((el, key) => <ProductPulse key={key} />)}
      </div>
    );
  }

  return <Component data={data} error={error} />;
};

Solution 2:[2]

Your API has been called when HocComponent gets rendered, so it won't wait for your API response.

Ideally, you should have loading state to wait for the fetch completed, and you also can set data state instead of param state in useEffect whenever urlParams has changed.

const withLoading = (WrappedComponent) => {
    const HocComponent = ({ ...props }) => {
        const [urlParams, setUrlParams] = useSearchParams()
        //`response` state to listen to API response changes
        const [response, setResponse] = useState({ data: null, error: null, loading: true })
        useEffect(() => {
            console.log(urlParams.get("text"));
            const param = urlParams.get("text");
            //`urlParams` gets changed and not undefined, we call API here
            if(urlParams.get("text")) {
               const { data, loading, error } = useFetch("api_server", "/articles", { 'text': param });
               setResponse({ data, loading, error })
            }

        }, [urlParams])

        const { loading, data, error } = response
        
        if (loading) return (
            <div className="grid grid-cols-6">
                {Array(6).map(el => <ProductPulse />)}
            </div>
        )
        return <WrappedComponent data={data} error={error} />
    }
    return HocComponent
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Drew Reese
Solution 2 Nick Vu