diff --git a/packages/web/components/Dashboard/Filters/SearchInput.tsx b/packages/web/components/Dashboard/Filters/SearchInput.tsx index 52baa32bf..dd60c5a05 100644 --- a/packages/web/components/Dashboard/Filters/SearchInput.tsx +++ b/packages/web/components/Dashboard/Filters/SearchInput.tsx @@ -1,6 +1,6 @@ -import React, { useCallback, useState } from 'react' -import _ from 'lodash' +import React, { useState } from 'react' import { useTranslation } from '@/config/i18n' +import useDebouncedCallback from '@/hooks/useDebouncedCallback' type Props = { defaultValue: string @@ -18,12 +18,9 @@ const SearchInput: React.FC = ({ defaultValue, onChange, debounceTime }) setValue(defaultValue) } - const debounceSearch = useCallback( - _.debounce((_searchVal: string) => { - onChange(_searchVal) - }, debounceTime), - [], - ) + const debounceSearch = useDebouncedCallback((searchVal: string) => { + onChange(searchVal) + }, debounceTime) const onSearchChange = (e: React.ChangeEvent): void => { setValue(e.target.value) diff --git a/packages/web/components/Dashboard/MyFeed/MyFeed.tsx b/packages/web/components/Dashboard/MyFeed/MyFeed.tsx index 71475d497..3a9d47d81 100644 --- a/packages/web/components/Dashboard/MyFeed/MyFeed.tsx +++ b/packages/web/components/Dashboard/MyFeed/MyFeed.tsx @@ -3,8 +3,6 @@ import Head from 'next/head' import { useRouter } from 'next/router' import { toast } from 'react-toastify' -import _ from 'lodash' - import { useTranslation } from '@/config/i18n' import PostCard from '../PostCard' diff --git a/packages/web/components/JournalyEditor/Toolbar/Toolbar.tsx b/packages/web/components/JournalyEditor/Toolbar/Toolbar.tsx index 987792c44..4a91226f0 100644 --- a/packages/web/components/JournalyEditor/Toolbar/Toolbar.tsx +++ b/packages/web/components/JournalyEditor/Toolbar/Toolbar.tsx @@ -31,6 +31,7 @@ import { options, isTableActive } from '../helpers' import SwitchToggle from '@/components/SwitchToggle' import { useTranslation } from '@/config/i18n' import useIntersectionObserver from '@/hooks/userIntersectionObserver' +import useDebouncedCallback from '@/hooks/useDebouncedCallback' type ToolbarProps = { allowInlineImages: boolean @@ -65,14 +66,16 @@ const Toolbar = ({ setViewportsDiff(visualViewport.offsetTop) } - onVisualViewportChange() + const debouncedOnVisualViewportChange = useDebouncedCallback(onVisualViewportChange, 500) - visualViewport.addEventListener('resize', onVisualViewportChange) - visualViewport.addEventListener('scroll', onVisualViewportChange) + debouncedOnVisualViewportChange() + + visualViewport.addEventListener('resize', debouncedOnVisualViewportChange) + visualViewport.addEventListener('scroll', debouncedOnVisualViewportChange) return () => { - visualViewport.removeEventListener('resize', onVisualViewportChange) - visualViewport.removeEventListener('scroll', onVisualViewportChange) + visualViewport.removeEventListener('resize', debouncedOnVisualViewportChange) + visualViewport.removeEventListener('scroll', debouncedOnVisualViewportChange) } }, []) diff --git a/packages/web/hooks/useDebouncedCallback.ts b/packages/web/hooks/useDebouncedCallback.ts new file mode 100644 index 000000000..b69b78afa --- /dev/null +++ b/packages/web/hooks/useDebouncedCallback.ts @@ -0,0 +1,31 @@ +import { useRef, useCallback } from 'react' + +/** + * Returns a memoized function that will only call the passed function when it hasn't been called for the wait period + * @param callback The function to be called + * @param wait Wait period after function hasn't been called for + * @returns A memoized function that is debounced + */ +const useDebouncedCallback = ( + callback: (...args: CallbackArgs) => void, + wait: number, +) => { + // Use a ref to store the timeout between renders + // and prevent changes to it from causing re-renders + const timeout = useRef() + + return useCallback( + (...args) => { + const later = () => { + clearTimeout(timeout.current) + callback(...args) + } + + clearTimeout(timeout.current) + timeout.current = setTimeout(later, wait) + }, + [callback, wait], + ) +} + +export default useDebouncedCallback