npm:@victorzimnikov/utility-hooks | Skypack
You need to enable JavaScript to run this app.
Usage no npm install needed!
<script type="module">
import victorzimnikovUtilityHooks from 'https://cdn.skypack.dev/@victorzimnikov/utility-hooks';
</script>
quot;
+ }
+ ]
}
Hooks
useEventCallback(callback)
Inspired by How to read an often-changing value from useCallback?
Unlike useCallback
, useEventCallback
does not accept second argument and stores original callback
in ref.
function Form() {
const [text, updateText] = useState("");
- const textRef = useRef();
-
- useEffect(() => {
- textRef.current = text; // Write it to the ref
- });
-
- const handleSubmit = useCallback(() => {
- const currentText = textRef.current; // Read it from the ref
- alert(currentText);
- }, [textRef]); // Don't recreate handleSubmit like [text] would do
+ const handleSubmit = useEventCallback(() => {
+ alert(text);
+ });
return (
<>
<input value={text} onChange={e => updateText(e.target.value)} />
<ExpensiveTree onSubmit={handleSubmit} />
</>
);
}
useIsomorphicLayoutEffect(effect, deps)
Inspired by react-redux/src/utils/useIsomorphicLayoutEffect
Runs useLayoutEffect
in browser environment (checks document.createElement
), otherwise useEffect
.
useConstant(factory)`
Inspired by How to create expensive objects lazily?
Runs factory only once and writes value in component ref
.
function Image(props) {
- const ref = useRef(null);
const node = useRef();
-
- // ✅ IntersectionObserver is created lazily once
- function getObserver() {
- let observer = ref.current;
- if (observer !== null) {
- return observer;
- }
- let newObserver = new IntersectionObserver(onIntersect);
- ref.current = newObserver;
- return newObserver;
- }
+ const observer = useConstant(() => new IntersectionObserver(onIntersect));
useEffect(() => {
- getObserver().observe(node.current);
+ observer.observe(node.current);
}, [observer]);
}
useMemoWith(factory, deps, isEqual)
Inspired by Gist .
Compares each dependency with isEqual
function to memoize value from factory
.
export function useFetch(url, options) {
- const cachedOptionsRef = useRef();
-
- if (
- !cachedOptionsRef.current ||
- !_.isEqual(options, cachedOptionsRef.current)
- ) {
- cachedOptionsRef.current = options;
- }
+ const cachedOptions = useMemoWith(() => options, [options], _.isEqual);
useEffect(() => {
// Perform fetch
- }, [url, cachedOptionsRef.current]);
+ }, [url, cachedOptions]);
}
usePrevious(value)
Inspired by How to get the previous props or state?
Stores value
used in previous render.
function Counter() {
- const prevCountRef = useRef();
const [count, setCount] = useState(0);
-
- useEffect(() => {
- prevCountRef.current = count;
- });
+ const prevCount = usePrevious(count);
return (
<h1>
- Now: {count}, before: {prevCountRef.current}
+ Now: {count}, before: {prevCount}
</h1>
);
}
usePromise(factory, deps)
Handles loading of promises created by factory
function.
const [filter, setFilter] = useState('')
- const [value, setValue] = useState();
- const [error, setError] = useState()
- useEffect(() => {
- const controller = new AbortController();
- const runEffect = async () => {
- try {
- const value = await fetch(
- "https://foo.bars/api?filter=" + filter,
- { signal: controller.signal }
- );
-
- setValue(value);
- } catch (error) {
- if (err.name === 'AbortError') {
- console.log("Request was canceled via controller.abort");
- return;
- }
-
- setError(error)
- }
- };
- runEffect();
- return () => controller.abort()
- }, [filter]);
+ const { value, error } = usePromise(({ abortSignal }) => fetch(
+ "https://foo.bars/api?filter=" + filter,
+ { signal: abortSignal }
+ ), [filter])
usePureMemo(deps, isEqual)
Returns next deps
only when they were changed based on isEqual
result.
usePureMemo(factory, deps, isEqual)
Works like useMemoWith
, but also compares return value.
export function useFetch(url, options) {
- const cachedOptionsRef = useRef();
-
- if (
- !cachedOptionsRef.current ||
- !_.isEqual(options, cachedOptionsRef.current)
- ) {
- cachedOptionsRef.current = options;
- }
+ const cachedOptions = usePureMemo(() => options, [options], _.isEqual);
useEffect(() => {
// Perform fetch
- }, [url, cachedOptionsRef.current]);
+ }, [url, cachedOptions]);
}
useValueRef(value)
Inspired by How to read an often-changing value from useCallback?
Works like useRef
, but keeps it's ref
in sync with value
on every call.
function Form() {
const [text, updateText] = useState('');
+ const textRef = useValueRef(text);
- const textRef = useRef();
-
- useEffect(() => {
- textRef.current = text; // Write it to the ref
- });
const handleSubmit = useCallback(() => {
const currentText = textRef.current; // Read it from the ref
alert(currentText);
}, [textRef]); // Don't recreate handleSubmit like [text] would do
return (
<>
<input value={text} onChange={e => updateText(e.target.value)} />
<ExpensiveTree onSubmit={handleSubmit} />
</>
);
}
useWhenValueChanges(value, effect, isEqual)
Works like useEffect
, but runs effect only when value
compared by isEqual
(Object.is
if not provided). It also passes the previous value
as an effect argument.
function List({ disptach, page, selectedId }) {
- const isInitial = useRef(true);
useEffect(() => {
- isInitial.current = true;
dispatch({ type: "FETCH_LIST", page });
}, [page, dispatch]);
useEffect(() => {
dispatch({ type: "FETCH_ITEM", id: selectedId });
}, [selectedId, dispatch]);
- useEffect(() => {
- if (isInitial.current) {
- isInitial.current = false;
- } else if (!selectedId) {
- dispatch({ type: "FETCH_LIST", page });
- }
- }, [page, selectedId, dispatch]);
+ useWhenValueChanges(selectedId, () => {
+ if (!selectedId) {
+ dispatch({ type: "FETCH_LIST", page });
+ }
+ });
}
Utilities
areDepsEqualWith(hookName, nextDeps, prevDeps, isEqual)
Compares each dependency with isEqual
function.
Details
Updated
February 3, 2021
Created
February 3, 2021
Package Security
added
ES Module Entrypoint
Export Map
Info
Keywords
Info
added
License
added
README
Repository URL
Info
added
TypeScript Types
License
MIT
Dependencies
0