1. useToggle
Basically, what this hook does is that, it takes a parameter with value true or false and toggles that value to opposite. It's useful when we want to take some action into it's opposite action.
For example;
- show and hide modal,
- show more/show less text,
- open/close side menu.
// Hook
// Parameter is the boolean, with default "false" value
const useToggle = (initialState = false) => {
// Initialize the state
const [state, setState] = useState(initialState);
// Define and memorize toggler function in case we pass down the comopnent,
// This function change the boolean value to it's opposite value
const toggle = useCallback(() => setState(state => !state), []);
return [state, toggle]
}
// Usage
function App() {
// Call the hook which returns, current value and the toggler function
const [isTextChanged, setIsTextChanged] = useToggle();
return (
<button onClick={setIsTextChanged}>
{isTextChanged ? 'Toggled' : 'Click to Toggle'}
</button>
);
}
2. useOnClickOutside
This hook allows you to detect clicks outside of a specified element.
By abstracting this logic out into a hook we can easily use it across all of our components that need this kind of functionality.
For Example;
- dropdown menus,
- tooltips,
- modals
- etc..
// Hook
const useOnClickOutside = (ref, handler) => {
useEffect(
() => {
const listener = (event) => {
// Do nothing if clicking ref's element or descendent elements
if (!ref.current || ref.current.contains(event.target)) {
return;
}
handler(event);
};
document.addEventListener("mousedown", listener);
document.addEventListener("touchstart", listener);
return () => {
document.removeEventListener("mousedown", listener);
document.removeEventListener("touchstart", listener);
};
},
[ref, handler]
);
}
// Usage
function App() {
// Create a ref that we add to the element for which we want to detect outside clicks
const ref = useRef();
// State for our modal
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>
);
}
3. useSubmit
Instead of recreating loading and form states we can also move that logic inside a hook called useSubmit
// Hook
const useSubmit = submitFunction => {
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const handleSubmit = async () => {
try {
setLoading(true);
setError(null);
await submitFunction();
} catch (error) {
setError(error);
} finally {
setLoading(false);
}
};
return [handleSubmit, loading, error];
};
// Usage
function App() {
const mySubmitFunction = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Timeout Finished")
}, 2000);
});
};
const [handleSubmit, loading, error] = useSubmit(mySubmitFunction);
return (
<div className="App">
<button onClick={handleSubmit} disabled={loading}>
{!loading ? "Click me" : "Loading..."}
</button>
{error && <div>{error}</div>}
</div>
);
}
4. useMediaQuery
If you want to write css in js or you just want to add some sideEffect to the specific device or breakpoint this hook is for you.
// Hook
const useMediaQuery = (query = "(min-width: 576px)") => {
const [matches, setMatches] = useState(false);
useEffect(() => {
const media = window.matchMedia(query);
if (media.matches !== matches) {
setMatches(media.matches);
}
const listener = () => {
setMatches(media.matches);
};
media.addListener(listener);
return () => media.removeListener(listener);
}, [matches, query]);
return matches;
}
// Usage
const isTablet = useMediaQuery("(max-width: 1200px)");