Skip to content

Instantly share code, notes, and snippets.

@brampersandon
Last active November 1, 2023 11:53
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brampersandon/8128a86f6383341ac54e25ca4f58c293 to your computer and use it in GitHub Desktop.
Save brampersandon/8128a86f6383341ac54e25ca4f58c293 to your computer and use it in GitHub Desktop.
Common hooks I use everywhere but don't want to install
import { useState, useCallback } from "react";
type AsyncStatus = 'notasked' | 'loading' | 'success' | 'error';
// from https://usehooks.com/useAsync/
export const useAsync = <T, E = string>(
asyncFunction: (...args: any[]) => Promise<T>,
) => {
const [status, setStatus] = useState<AsyncStatus>('notasked');
const [value, setValue] = useState<T | null>(null);
const [error, setError] = useState<E | null>(null);
// The execute function wraps asyncFunction and
// handles setting state for pending, value, and error.
// useCallback ensures the below useEffect is not called
// on every render, but only if asyncFunction changes.
const execute = useCallback(
(...args) => {
setStatus('loading');
setValue(null);
setError(null);
return asyncFunction(...args)
.then((response: any) => {
setValue(response);
setStatus('success');
})
.catch((error: any) => {
setError(error);
setStatus('error');
});
},
[asyncFunction],
);
return { execute, status, value, error };
};
// Extracted from https://github.com/donavon/use-interval/blob/master/src/index.js
import { useEffect, useRef } from "react";
type Callback = (args?: any) => void;
const useInterval = (callback: Callback, delay: number) => {
const savedCallback = useRef<Callback>();
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
useEffect(() => {
const handler: Callback = (...args) =>
savedCallback.current && savedCallback.current(...args);
if (delay !== null) {
// Run immediately:
setImmediate(handler);
// Then run every interval:
const id = setInterval(handler, delay);
return () => clearInterval(id);
}
}, [delay]);
};
export default useInterval;
import { useState } from "react";
// from: https://usehooks.com/useLocalStorage/
function useLocalStorage<T>(
key: string,
initialValue: T
): [T, (arg: T) => void] {
// State to store our value
// Pass initial state function to useState so logic is only executed once
const [storedValue, setStoredValue] = useState(() => {
try {
// Guard for SSR
if (typeof window === "undefined") return initialValue;
// 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
//console.log(error);
return initialValue;
}
});
// Return a wrapped version of useState's setter function that ...
// ... persists the new value to localStorage.
const setValue = (value: 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);
// Guard for SSR
if (typeof window === "undefined") return initialValue;
// Save to local storage
window.localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
// A more advanced implementation would handle the error case
//console.log(error);
}
};
return [storedValue, setValue];
}
export default useLocalStorage;
import { useEffect, useRef } from 'react'
// Adapted from: https://github.com/siddharthkp/use-timeout/blob/master/index.js
function useTimeout(callback, delay) {
const savedCallback = useRef()
// Remember the latest callback.
useEffect(
() => {
savedCallback.current = callback
},
[callback]
)
// Set up the interval.
useEffect(
() => {
function tick() {
const callable = savedCallback.current || (() => {})
callable();
}
if (delay !== null) {
const id = setTimeout(tick, delay)
return () => clearTimeout(id)
}
},
[delay]
)
}
export default useTimeout
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment