title: Debouncing and Timeout in React
body: <p>I have a here a input field that on every type, it dispatches a redux action.
  I have put a useDebounce in order that it won't be very heavy. The problem is that it says <code>Hooks can only be called inside of the body of a function component.</code> What is the proper way to do it?</p>
  <p><strong>useTimeout</strong></p>
  <pre><code>import { useCallback, useEffect, useRef } from &quot;react&quot;;
  
  export default function useTimeout(callback, delay) {
    const callbackRef = useRef(callback);
    const timeoutRef = useRef();
  
    useEffect(() =&gt; {
      callbackRef.current = callback;
    }, [callback]);
  
    const set = useCallback(() =&gt; {
      timeoutRef.current = setTimeout(() =&gt; callbackRef.current(), delay);
    }, [delay]);
  
    const clear = useCallback(() =&gt; {
      timeoutRef.current &amp;&amp; clearTimeout(timeoutRef.current);
    }, []);
  
    useEffect(() =&gt; {
      set();
      return clear;
    }, [delay, set, clear]);
  
    const reset = useCallback(() =&gt; {
      clear();
      set();
    }, [clear, set]);
  
    return { reset, clear };
  }
  </code></pre>
  <p><strong>useDebounce</strong></p>
  <pre><code>import { useEffect } from &quot;react&quot;;
  import useTimeout from &quot;./useTimeout&quot;;
  
  export default function useDebounce(callback, delay, dependencies) {
    const { reset, clear } = useTimeout(callback, delay);
    useEffect(reset, [...dependencies, reset]);
    useEffect(clear, []);
  }
  </code></pre>
  <p><strong>Form component</strong></p>
  <pre><code>import React from &quot;react&quot;;
  import TextField from &quot;@mui/material/TextField&quot;;
  import useDebounce from &quot;../hooks/useDebounce&quot;;
  
  export default function ProductInputs(props) {
    const { handleChangeProductName = () =&gt; {} } = props;
  
    return (
      &lt;TextField
        fullWidth
        label=&quot;Name&quot;
        variant=&quot;outlined&quot;
        size=&quot;small&quot;
        name=&quot;productName&quot;
        value={formik.values.productName}
        helperText={formik.touched.productName ? formik.errors.productName : &quot;&quot;}
        error={formik.touched.productName &amp;&amp; Boolean(formik.errors.productName)}
        onChange={(e) =&gt; {
          formik.setFieldValue(&quot;productName&quot;, e.target.value);
          useDebounce(() =&gt; handleChangeProductName(e.target.value), 1000, [
            e.target.value,
          ]);
        }}
      /&gt;
    );
  }
  </code></pre>