From 76de3c5183bd3044f1a8d1a5c67238699459e14b Mon Sep 17 00:00:00 2001 From: Dave Morse Date: Fri, 31 Jan 2020 08:18:25 -0600 Subject: [PATCH] Add bouncyFirstRun option to useDebounce. Rejigger arguments to use options hash. --- app/javascript/dance-table.tsx | 5 +++- app/javascript/use-debounce.ts | 43 ++++++++++++++++++---------------- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/app/javascript/dance-table.tsx b/app/javascript/dance-table.tsx index 2382248f..60cb897b 100644 --- a/app/javascript/dance-table.tsx +++ b/app/javascript/dance-table.tsx @@ -207,7 +207,10 @@ function Table({ if (!columnDefinitions[i].show) columns[i].toggleHidden(true) }, [columns]) - const debouncedFilter = useDebounce(filter, 800) + const debouncedFilter = useDebounce(filter, { + delay: 800, + bouncyFirstRun: true, + }) // again, need to worry about the return value of this first arg to useEffect useEffect( diff --git a/app/javascript/use-debounce.ts b/app/javascript/use-debounce.ts index 282f3113..2e12389e 100644 --- a/app/javascript/use-debounce.ts +++ b/app/javascript/use-debounce.ts @@ -1,29 +1,32 @@ // from https://dev.to/gabe_ragland/debouncing-with-react-hooks-jci -import React, { useState, useEffect } from "react" +import React, { useState, useEffect, useRef } from "react" -// Our hook -export default function useDebounce(value: T, delay: number): T { - // State and setters for debounced value +export default function useDebounce( + value: T, + { + delay = 800, + bouncyFirstRun = false, + }: { delay: number; bouncyFirstRun: boolean } = { + delay: 800, + bouncyFirstRun: false, + } +): T { const [debouncedValue, setDebouncedValue] = useState(value) - + const isFirstRun = useRef(true) useEffect(() => { - // Set debouncedValue to value (passed in) after the specified delay - const handler = setTimeout(() => { + if (bouncyFirstRun && isFirstRun.current) { + isFirstRun.current = false setDebouncedValue(value) - }, delay) - - // Return a cleanup function that will be called every time ... - // ... useEffect is re-called. useEffect will only be re-called ... - // ... if value changes (see the inputs array below). - // This is how we prevent debouncedValue from changing if value is ... - // ... changed within the delay period. Timeout gets cleared and restarted. - // To put it in context, if the user is typing within our app's ... - // ... search box, we don't want the debouncedValue to update until ... - // ... they've stopped typing for more than 500ms. - return () => { - clearTimeout(handler) - } // Only re-call effect if value changes + } else { + const handler = setTimeout(() => { + console.log("setTimeout resolve") + setDebouncedValue(value) + }, delay) + return () => { + clearTimeout(handler) + } + } }, [value]) return debouncedValue