Skip to content

Commit

Permalink
Add bouncyFirstRun option to useDebounce. Rejigger arguments to use o…
Browse files Browse the repository at this point in the history
…ptions hash.
  • Loading branch information
dcmorse committed Jan 31, 2020
1 parent f0d4641 commit 76de3c5
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 21 deletions.
5 changes: 4 additions & 1 deletion app/javascript/dance-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
43 changes: 23 additions & 20 deletions app/javascript/use-debounce.ts
Original file line number Diff line number Diff line change
@@ -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<T>(value: T, delay: number): T {
// State and setters for debounced value
export default function useDebounce<T>(
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
Expand Down

0 comments on commit 76de3c5

Please sign in to comment.