Skip to content

Instantly share code, notes, and snippets.

@zempo
Last active October 26, 2022 14:06
Show Gist options
  • Save zempo/a9a71f2a6d395b0a70d94b55bd1ab1aa to your computer and use it in GitHub Desktop.
Save zempo/a9a71f2a6d395b0a70d94b55bd1ab1aa to your computer and use it in GitHub Desktop.
My collection of custom React Hooks
My ongoing collection of custom react hooks.
I always reference this snippet whenever starting a new react project.
import { useEffect } from "react";
import { withRouter } from "react-router-dom";
/*
USAGE
------------------------------
import ScrollToTop from "./hooks/ScrollToTop";
export const App = () => {
return (
<>
<ScrollToTop />
<main>
<Switch>
{Children...}
</Switch>
</main>
</>
)
}
-------------------------
*
*/
function ScrollToTop({ history }) {
useEffect(() => {
const unlisten = history.listen(() => {
window.scrollTo(0, 0);
});
return () => {
unlisten();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return null;
}
export default withRouter(ScrollToTop);
import { useState, useEffect } from "react";
/*
* USAGE
---------------------------------
export const myComponent = () => {
let height = useCurrentHeight();
return (
<>
{height}
</>
)
}
---------------------------------
*/
const getHeight = () =>
window.innerHeight ||
document.documentElement.clientHeight ||
document.body.clientHeight;
export function useCurrentHeight() {
// save current window width in the state object
let [height, setHeight] = useState(getHeight());
// in this case useEffect will execute only once because
// it does not have any dependencies.
useEffect(() => {
// timeoutId for debounce mechanism
let timeoutId = null;
const resizeListener = () => {
// prevent execution of previous setTimeout
clearTimeout(timeoutId);
// change height from the state object after 150 milliseconds
timeoutId = setTimeout(() => setHeight(getHeight()), 150);
};
// set resize listener
window.addEventListener("resize", resizeListener);
// clean up function
return () => {
// remove resize listener
window.removeEventListener("resize", resizeListener);
};
}, []);
return height;
}
import { useState, useEffect } from "react";
/*
* USAGE
---------------------------------
export const myComponent = () => {
let width = useCurrentWidth();
return (
<>
{width}
</>
)
}
---------------------------------
*/
const getWidth = () =>
window.innerWidth ||
document.documentElement.clientWidth ||
document.body.clientWidth;
export function useCurrentWidth() {
// save current window width in the state object
let [width, setWidth] = useState(getWidth());
// in this case useEffect will execute only once because
// it does not have any dependencies.
useEffect(() => {
// timeoutId for debounce mechanism
let timeoutId = null;
const resizeListener = () => {
// prevent execution of previous setTimeout
clearTimeout(timeoutId);
// change width from the state object after 150 milliseconds
timeoutId = setTimeout(() => setWidth(getWidth()), 150);
};
// set resize listener
window.addEventListener("resize", resizeListener);
// clean up function
return () => {
// remove resize listener
window.removeEventListener("resize", resizeListener);
};
}, []);
return width;
}
import { useContext, useLayoutEffect, useRef, useState } from "react";
/**
* Hook Creator: https://swizec.com/blog/usedimensions-a-react-hook-to-measure-dom-nodes/
* GitHub: https://github.com/Swizec/useDimensions
*
* This hook has been modified to work on window resize
*
* USAGE
----------------------------
export const myComponent = () => {
const [elRef, elSize] = useDimensions();
return (
<>
<div ref={elRef}>
{elSize}
</div>
</>
)
}
----------------------------
*
*/
export const useDimensions = () => {
const ref = useRef();
const [dimensions, setDimensions] = useState({});
useLayoutEffect(() => {
function handleResize() {
setDimensions(ref.current.getBoundingClientRect().toJSON());
}
// call on mount
handleResize();
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ref.current]);
return [ref, dimensions];
};
import { useState } from "react";
/*
* USAGE
---------------------------- index.html
<div id="root"></div>
<div id="modal"></div>
----------------------------
---------------------------- Modal.js
import React from "react";
import ReactDOM from "react-dom";
export const Modal = ({isShowing, hide}) => {
if (isShowing) {
return ReactDOM.createPortal(
<div onClick={hide} className='Modal'>
<div
onClick={(e) => e.stopPropagation()}
className={`Modal__inner ${isShowing}`}
>
</div>
</div>,
document.querySelector("#modal")
);
} else {
return null;
}
}
----------------------------
---------------------------- MyComponent.js
export const myComponent = () => {
const { isShowing: isShowingItem, toggle: toggleItem } =
useModal();
const openItem = () => {
toggleItem();
};
return (
<>
<div>
<button className={`open-item`} onClick={openItem}>
<span>See More</span>
</button>
</div>
<Modal
isShowing={isShowingItem}
hide={toggleItem}
/>
</>
)
}
----------------------------
*/
export const useModal = () => {
const [isShowing, setIsShowing] = useState(false);
function toggle() {
setIsShowing(!isShowing);
}
return {
isShowing,
toggle,
};
};
import { useDrag } from "react-use-gesture";
/**
* HOOK CREDITS
* -------------
*
* @WilliamIPark
* https://codesandbox.io/s/w77ui?file=/src/index.js
*/
const anonFn = () => {};
export default function useSwipe(
actions = {
onUp: anonFn,
onDown: anonFn,
onLeft: anonFn,
onRight: anonFn,
},
threshold = 0.3
) {
const bind = useDrag(({ last, vxvy: [vx, vy] }) => {
if (Math.abs(vx) > Math.abs(vy)) {
if (vx < -threshold && last) {
actions.onLeft();
} else if (vx > threshold && last) {
actions.onRight();
}
} else {
if (vy < -threshold && last) {
actions.onUp();
} else if (vy > threshold && last) {
actions.onDown();
}
}
});
return bind;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment