From c6aa70a64731b608fade3acab48c1d1d2df280b6 Mon Sep 17 00:00:00 2001 From: 0t4u <61939142+0t4u@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:33:28 +0000 Subject: Add files via upload --- modules/hooks/useAnimationFrame.tsx | 30 +++++++++++++++++++++++ modules/hooks/useDebounce.tsx | 25 +++++++++++++++++++ modules/hooks/useLocalStorage.tsx | 48 +++++++++++++++++++++++++++++++++++++ modules/hooks/useThrottle.tsx | 24 +++++++++++++++++++ modules/hooks/useWindowSize.tsx | 19 +++++++++++++++ 5 files changed, 146 insertions(+) create mode 100644 modules/hooks/useAnimationFrame.tsx create mode 100644 modules/hooks/useDebounce.tsx create mode 100644 modules/hooks/useLocalStorage.tsx create mode 100644 modules/hooks/useThrottle.tsx create mode 100644 modules/hooks/useWindowSize.tsx (limited to 'modules/hooks') diff --git a/modules/hooks/useAnimationFrame.tsx b/modules/hooks/useAnimationFrame.tsx new file mode 100644 index 0000000..ce7f8f6 --- /dev/null +++ b/modules/hooks/useAnimationFrame.tsx @@ -0,0 +1,30 @@ +import React from "react"; + +/** + * React hook to request animation frame + * + * Taken from https://css-tricks.com/using-requestanimationframe-with-react-hooks/ + */ +export const useAnimationFrame = ( + callback: (deltaTime: number) => void, + dependencies: any[] = [] +) => { + // Use useRef for mutable variables that we want to persist + // without triggering a re-render on their change + const requestRef = React.useRef(0); + const previousTimeRef = React.useRef(0); + + const animate = (time: number) => { + if (previousTimeRef.current != undefined) { + const deltaTime = time - previousTimeRef.current; + callback(deltaTime); + } + previousTimeRef.current = time; + requestRef.current = requestAnimationFrame(animate); + }; + + React.useEffect(() => { + requestRef.current = requestAnimationFrame(animate); + return () => cancelAnimationFrame(requestRef.current); + }, dependencies); +}; diff --git a/modules/hooks/useDebounce.tsx b/modules/hooks/useDebounce.tsx new file mode 100644 index 0000000..6864217 --- /dev/null +++ b/modules/hooks/useDebounce.tsx @@ -0,0 +1,25 @@ +import React from "react"; + +export function useDebounce(value: any, delay: number) { + // State and setters for debounced value + const [debouncedValue, setDebouncedValue] = React.useState(value); + + React.useEffect( + () => { + // Update debounced value after delay + const handler = setTimeout(() => { + setDebouncedValue(value); + }, delay); + + // Cancel the timeout if value changes (also on delay change or unmount) + // This is how we prevent debounced value from updating if value is changed ... + // .. within the delay period. Timeout gets cleared and restarted. + return () => { + clearTimeout(handler); + }; + }, + [value, delay] // Only re-call effect if value or delay changes + ); + + return debouncedValue; +} diff --git a/modules/hooks/useLocalStorage.tsx b/modules/hooks/useLocalStorage.tsx new file mode 100644 index 0000000..60bd037 --- /dev/null +++ b/modules/hooks/useLocalStorage.tsx @@ -0,0 +1,48 @@ +import React from "react"; + +/** + * https://usehooks.com/useLocalStorage/ + */ +export function useLocalStorage( + key: string, + initialValue: T +): [T, (value: T | ((val: T) => T)) => void] { + // State to store our value + // Pass initial state function to useState so logic is only executed once + const [storedValue, setStoredValue] = React.useState(() => { + // try { + // // Get from local storage by key + // const item = window.localStorage.getItem(key); + // // Parse stored json or if none return initialValue + // return item ? JSON.parse(item) : initialValue; + // } catch (error) { + // If error also return initialValue + return initialValue; + // } + }); + + React.useEffect(() => { + // Get from local storage by key + const item = window.localStorage.getItem(key); + // Parse stored json or if none return initialValue + if (item) setStoredValue(JSON.parse(item)); + }, []); + + // Return a wrapped version of useState's setter function that ... + // ... persists the new value to localStorage. + const setValue = (value: T | ((val: T) => T)) => { + try { + // Allow value to be a function so we have same API as useState + const valueToStore = + value instanceof Function ? value(storedValue) : value; + + // Save state + setStoredValue(valueToStore); + + // Save to local storage + window.localStorage.setItem(key, JSON.stringify(valueToStore)); + } catch (error) {} + }; + + return [storedValue, setValue]; +} diff --git a/modules/hooks/useThrottle.tsx b/modules/hooks/useThrottle.tsx new file mode 100644 index 0000000..77c9731 --- /dev/null +++ b/modules/hooks/useThrottle.tsx @@ -0,0 +1,24 @@ +/** + * https://github.com/bhaskarGyan/use-throttle/blob/master/src/index.js + */ +import { useState, useEffect, useRef } from "react"; + +export const useThrottle = (value, limit) => { + const [throttledValue, setThrottledValue] = useState(value); + const lastRan = useRef(Date.now()); + + useEffect(() => { + const handler = setTimeout(function () { + if (Date.now() - lastRan.current >= limit) { + setThrottledValue(value); + lastRan.current = Date.now(); + } + }, limit - (Date.now() - lastRan.current)); + + return () => { + clearTimeout(handler); + }; + }, [value, limit]); + + return throttledValue; +}; diff --git a/modules/hooks/useWindowSize.tsx b/modules/hooks/useWindowSize.tsx new file mode 100644 index 0000000..0b72c9e --- /dev/null +++ b/modules/hooks/useWindowSize.tsx @@ -0,0 +1,19 @@ +import React from "react"; + +export const useWindowSize = () => { + const [innerWidth, setInnerWidth] = React.useState(null); + const [innerHeight, setInnerHeight] = React.useState(null); + + const handleResize = () => { + setInnerWidth(window.innerWidth); + setInnerHeight(window.innerHeight); + }; + + React.useEffect(() => { + handleResize(); + window.addEventListener("resize", handleResize); + return () => window.removeEventListener("resize", handleResize); + }, []); + + return { innerWidth, innerHeight }; +}; -- cgit v1.2.3