A React Hooks utility library containing popular customized hooks
What's your favorite dish?
npm i react-recipes --save
yarn add react-recipes
Name | Returns | Arguments |
---|---|---|
🍪 useCookie |
[cookieValue, updateCookie, deleteCookie] | (cookieName, initialValue) |
🥠 useCopyClipboard |
[isCopied, setIsCopied] | (duration: 2000) |
🍩 useDarkMode |
[enabled, setEnabledState] | - |
🍜 useDebounce |
debouncedValue | (value, delay) |
🥡 useDimensions |
[ref, dimensions, node] | (liveMeasure: true, delay: 250, initialDimensions: {}, effectDependencies: []) |
🍳 useEventListener |
- | (eventName, handle, element: window) |
🌯 useGeolocation |
{ latitude, longitude, timestamp, accuracy, error } | (watch: false, settings: {enableHighAccuracy: false, timeout: Infinity, maximumAge: 0}) |
🌭 useHover |
[callbackRef, value] | - |
🍦 useInterval |
[delay, ...effectDependencies] | (callback, delay, runOnLoad: false, effectDependencies: []) |
🍐 useIsClient |
isClient | |
🥧 useKeyPress |
keyPressed | (targetKey) |
🍱 useLocalStorage |
[storedValue, setValue] | (key, initialValue) |
🍋 useLockBodyScroll |
- | - |
🍉 useMedia |
value | (queries, values, defaultValue) |
🥭 useMultiKeyPress |
keysPressed | (targetKey) |
🥑 useOnClickOutside |
- | (ref, callback) |
🍿 usePrevious |
previous | (value) |
🍣 useScript |
[loaded, error] | (src) |
🍏 useThrottle |
throttledValue | (value, ms: 250) |
🍷 useWhyDidYouUpdate |
- | (name, props) |
🥖 useWindowScroll |
{ x, y } | - |
🥮 useWindowSize |
{ height, width } | (initialWidth, initialHeight) |
Create, read, or delete cookies (mmmm...cookie)
cookieName: String
: Name of cookieinitialValue?: String
: First value of cookie
cookieValue: String
: Current value of the cookieupdateCookie: Function
: Set a new value of the cookiedeleteCookie: Function
: Bye bye cookie
import { useCookie } from "react-recipes";
const App = () => {
const [userToken, setUserToken, deleteUserToken] = useCookie('token', '0');
render(
<div>
<p>{userToken}</p>
<button onClick={() => setUserToken('123')}>Change token</button>
<button onClick={() => deleteUserToken()}>Delete token</button>
</div>
);
};
Copies any string to the clipboard
duration?: Number
: Duration of "on/success" state, default is2000
.
isCopied: Bool
: true when string was copied for the length of the duration.setIsCopied: Function
: Copies the string to the clipboard
import { useCopyClipboard } from "react-recipes";
const App = () => {
const [isCopied, setIsCopied] = useCopyClipboard();
const copy = () => {
setIsCopied("This string is copied");
};
return (
<button onClick={copy} type="button">
{isCopied ? "Copied" : "Copy"}
</button>
);
};
Toggles (and saves to localStorage) dark mode
darkMode: Bool
: true when dark.setDarkMode: Function
: Toggles darkMode
import { useDarkMode } from "react-recipes";
function App() {
const [darkMode, setDarkMode] = useDarkMode();
return (
<div>
<div className="navbar">
<Toggle darkMode={darkMode} setDarkMode={setDarkMode} />
</div>
<Content />
</div>
);
}
Debounce any fast changing value
value: Any
: value to be debounceddelay: Number
: Delay of debounce
debouncedValue: Any
: Equal to the value passed in
import { useDebounce } from "react-recipes";
const App = () => {
const [searchTerm, setSearchTerm] = useState('');
const [results, setResults] = useState([]);
const [isSearching, setIsSearching] = useState(false);
// Debounce search term so that it only gives us latest value ...
// ... if searchTerm has not been updated within last 500ms.
const debouncedSearchTerm = useDebounce(searchTerm, 500);
// Effect for API call
useEffect(
() => {
if (debouncedSearchTerm) {
setIsSearching(true);
searchCharacters(debouncedSearchTerm).then(results => {
setIsSearching(false);
setResults(results);
});
} else {
setResults([]);
}
},
[debouncedSearchTerm]
);
...
};
Gives the dimensions of any element
liveMeasure?: Bool
: Adds scroll and resize events to always have the latest dimensions, default istrue
.delay?: Number
: delay for debounce calculation, default is250
.initialDimensions?: Object
: Default dimensions before the calculation. Default is{}
.effectDependencies?: Array
: List of effects to re-call useLayoutEffect, default is[]
.
ref: Ref
: Give this ref to the element needing the calculationdimensions: Object
: All of the element's dimensionsnode: Node
: The Element
import { useDimensions } from "react-recipes";
function App() {
const [wrapperRef, dimensions] = useDimensions();
return (
<div ref={wrapperRef}>
height: {dimensions.height}
width: {dimensions.width}
</div>
);
}
Adds an event listener
eventName: String
: Name of event. Required.handler: Function
: Callback function. Required.element?: Element
: Element to attach the eventListener, default iswindow
.
import { useEventListener } from "react-recipes";
function App() {
// State for storing mouse coordinates
const [coords, setCoords] = useState({ x: 0, y: 0 });
// Event handler utilizing useCallback ...
// ... so that reference never changes.
const handler = useCallback(
({ clientX, clientY }) => {
// Update coordinates
setCoords({ x: clientX, y: clientY });
},
[setCoords]
);
// Add event listener using our hook
useEventListener("mousemove", handler);
return (
<h1>
The mouse position is ({coords.x}, {coords.y})
</h1>
);
}
Gets and watches for the geolocation of the user
watch?: Bool
: set it to true to follow the location. Default isfalse
settings: Object
: position options- settings.enableHighAccuracy: indicates the application would like to receive the most accurate results (default false),
- settings.timeout: maximum length of time (in milliseconds) the device is allowed to take in order to return a position (default Infinity),
- settings.maximumAge: the maximum age in milliseconds of a possible cached position that is acceptable to return (default 0).
position: Object
:- latitude
- longitude
- timestamp: the time when their location was given
- accuracy: how accuate the geolocation is
- error: Any error with getting the geolocation
import { useGeolocation } from "react-recipes";
function App() {
const { latitude, longitude, timestamp, accuracy, error } = useGeolocation(
true
);
return (
<code>
latitude: {latitude}
longitude: {longitude}
timestamp: {timestamp}
accuracy: {accuracy && `${accuracy}m`}
error: {error}
</code>
);
}
Know when the mouse if hovering over an element
hoverRef: Ref
: add this to the desired hover elementisHovered: Bool
: Whether or not the mouse is currently hovering over element
import { useHover } from "react-recipes";
function App() {
const [hoverRef, isHovered] = useHover();
return <div ref={hoverRef}>{isHovered ? "😁" : "☹️"}</div>;
}
Makes setInterval
way easier
callback: Function
: Callback after each intervaldelay: Number
: delay time between each callback invocationrunOnLoad?: Bool
: Whether or not to run interval on mount, default is false.effectDependencies?: Array
: List of effects to re-call callback, default is[]
.
isCopied: Bool
: true when string was copied for the length of the duration.setIsCopied: Function
: Copies the string to the clipboard
import { useInterval } from "react-recipes";
const App = () => {
// Grabs user data every 7500ms or when user changes
useInterval(() => {
if (user) {
getUserInfo(user);
}
}, 7500, true, [user]);
...
};
Check if the javascript is loaded from the web client
isClient: Bool
: true when window is available. False when server side rendered
import { useIsClient } from "react-recipes";
const App = () => {
const isClient = useIsClient();
return <div>{isClient && "client side rendered"}</div>;
};
Adds keydown/keyup listeners to any key
targetKey: String
: A key on the keyboard. Required
keyPressed: Bool
: true on keydown are the targetKey.
import { useKeyPress } from "react-recipes";
function App() {
const happyPress = useKeyPress("h");
return <div>{happyPress && "😊"}</div>;
}
Store and set values into localStorage
key: String
: A unique key to be stored in localStorageinitialValue: String
: Value to be used the first time for localStorage
storedValue: String
: Value in localStoragesetValue: Function
: Set a new value to localStorage
import { useLocalStorage } from "react-recipes";
function App() {
// Similar to useState but first arg is key to the value in local storage.
const [name, setName] = useLocalStorage("name", "Bob");
return (
<div>
<input
type="text"
placeholder="Enter your name"
value={name}
onChange={e => setName(e.target.value)}
/>
</div>
);
}
Locks the scrolling - used for things like modals
import { useLockBodyScroll } from "react-recipes";
function App() {
const [isOpen, setIsOpen] = useState(false);
return (
isOpen && (
<Modal title="The title" onClose={() => setIsOpen(false)}>
Great modal content!
</Modal>
)
);
}
function Modal({ title, children, onClose }) {
// Call hook to lock body scroll
useLockBodyScroll();
return (
<div className="modal-overlay" onClick={onClose}>
<div className="modal">
<h2>{title}</h2>
<p>{children}</p>
</div>
</div>
);
}
Media Queries for Javascript
queries: Array
: List of Media Query stringsvalues: Array
: List of values tha correlates to the query listdefaultValue: Any
: default value of media query
value: Any
:
import { useMedia } from "react-recipes";
function App() {
// See if user has set a browser or OS preference for dark mode.
const prefersDarkMode = useMedia(
["(prefers-color-scheme: dark)"],
[true],
false
);
const columnCount = useMedia(
// Media queries
["(min-width: 1500px)", "(min-width: 1000px)", "(min-width: 600px)"],
// Column counts (relates to above media queries by array index)
[5, 4, 3],
// Default column count
2
);
let columnHeights = new Array(columnCount).fill(0);
let columns = new Array(columnCount).fill().map(() => []);
return (
<div>
<input
type="text"
placeholder="Enter your name"
value={name}
onChange={e => setName(e.target.value)}
/>
</div>
);
}
Listens for mulitple keypresses at a time
keysPressed: Set
: A set a keys currently pressed
import { useMultiKeyPress } from "react-recipes";
function App() {
const keysPressed = useMultiKeyPress();
return <div>{[...keysPressed].map(key => `${key} key pressed`)}</div>;
}
Event listener for clicking outside of an element
ref: Ref
: Click outside of this elementcallback: Function
: Called on click outside
import { useOnClickOutside } from "react-recipes";
function App() {
// Create a ref that we add to the element for which we want to detect outside clicks
const ref = useRef();
const [isModalOpen, setModalOpen] = useState(false);
// Call hook passing in the ref and a function to call on outside click
useOnClickOutside(ref, () => setModalOpen(false));
return (
<div>
{isModalOpen ? (
<div ref={ref}>
👋 Hey, I'm a modal. Click anywhere outside of me to close.
</div>
) : (
<button onClick={() => setModalOpen(true)}>Open Modal</button>
)}
</div>
);
}
Returns the previously set value
value: Any
: The current value (next value to save)
previous: Any
: The previous value
import { usePrevious } from "react-recipes";
function App() {
const [count, setCount] = useState(0);
// Get the previous value (was passed into hook on last render)
const prevCount = usePrevious(count);
return (
<div>
<h1>Now: {count}, before: {prevCount}</h1>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
Creates a script tag and loads the script
src: String
: The source url to the script
loaded: Bool
: Did the script load?error: Bool
: Did the script error out?
import { useScript } from "react-recipes";
function App() {
const [loaded, error] = useScript(
'https://pm28k14qlj.codesandbox.io/test-external-script.js'
);
return (
<div>
<div>
Script loaded: <b>{loaded.toString()}</b>
</div>
{loaded && !error && (
<div>
Script function call response: <b>{TEST_SCRIPT.start()}</b>
</div>
)}
</div>
);
}
Throttles a value
value: Any
: The value to be throttledms: Number
: The time in milliseconds to throttle
throttledValue: Any
: The returned value after the throttling
import { useThrottle } from "react-recipes";
const App = ({ value }) => {
const throttledValue = useThrottle(value, 250);
return (
<>
<div>Value: {value}</div>
<div>Throttled value: {throttledValue}</div>
</>
);
};
Console logs the reason for why a component updated
name: String
: Name this logprops: Object
: Component props from parent
import { useWhyDidYouUpdate } from "react-recipes";
// Let's pretend this <Counter> component is expensive to re-render so ...
// ... we wrap with React.memo, but we're still seeing performance issues :/
// So we add useWhyDidYouUpdate and check our console to see what's going on.
const Counter = React.memo(props => {
useWhyDidYouUpdate('Counter', props);
return <div style={props.style}>{props.count}</div>;
});
Re-renders on window scroll.
state: Object
x: Number
: Horizontal locationy: Number
: Vertical location
import { useWindowScroll } from "react-recipes";
const App = () => {
const { x, y } = useWindowScroll();
return (
<div>
<div>x: {x}</div>
<div>y: {y}</div>
</div>
);
};
Gets the window size and listens for resizes
src: String
: The source url to the script
loaded: Bool
: Did the script load?error: Bool
: Did the script error out?
import { useWindowSize } from "react-recipes";
function App() {
const { width, height } = useWindowSize();
return (
<div>
{width}px / {height}px
</div>
);
}